home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / ddj0897.zip / DYN401.ZIP / dpp / dpp.c < prev    next >
C/C++ Source or Header  |  1996-12-08  |  86KB  |  3,299 lines

  1.  
  2.  
  3.  
  4. /*                                      
  5.  *
  6.  *      Copyright (c) 1993-1996 Algorithms Corporation
  7.  *      3020 Liberty Hills Drive
  8.  *      Franklin, TN 37067
  9.  *
  10.  *      ALL RIGHTS RESERVED.
  11.  *
  12.  *      
  13.  *      
  14.  */
  15.  
  16.  
  17. #include "generics.h"
  18. #include <ctype.h>
  19. #include <string.h>
  20. #include "dpp.h"
  21.  
  22. #define MACROS
  23.  
  24. #define BUFSIZE        256
  25. #define MAXWORDSZ    80
  26.  
  27. /*  Used for Debugging the Interface between generics and methods  */
  28. /*  #define    DBI  */
  29.  
  30. #ifdef    unix
  31. #define RMODE    "r"
  32. #define WMODE    "w"
  33. #else
  34. #define RMODE    "rt"
  35. #define WMODE    "wt"
  36. #endif
  37.  
  38.  
  39. #ifdef    SYMC32
  40. #include <dos.h>
  41. EXPAND_WILDCARDS    /*  causes command line wild card expansion  */
  42. #endif
  43.  
  44. #if 0
  45. static    char    MPREFIX[80] = "m_";
  46. static    char    MSUFFIX[80];
  47.  
  48. static    char    OLMPREFIX[80] = "v_";
  49. static    char    OLMSUFFIX[80];
  50. #endif
  51.  
  52.  
  53. #define strne(a, b)    strcmp(a, b)
  54. #define streq(a, b)    !strcmp(a, b)
  55.  
  56. #define istart(x)    (isalpha(x)  ||  (x) == '_')
  57. #define irest(x)    (isalnum(x)  ||  (x) == '_')
  58.  
  59. static    int    SeeCode;    /*  read tokens inside braces    */
  60. static    long    CurrentLine;
  61.  
  62.     int    ErrorCode = 0;
  63. static    int    InKernel  = 0;
  64. static    int    NoProto   = 0;
  65. static    int    Quiet     = 0;
  66. static    int    GenIncludes = 1;
  67. static    int    MacroGuard  = 0;
  68. static    int    Copyright = 0;
  69. static    int    AllowOverloads = 0;
  70. static    int    Strategy = DPP_STRATEGY;/*  1=assembler, 2=C no assem,
  71.                         3=C++ inline,4=C++ inline except
  72.                         vararg generics  */
  73. static    int    FastWideCache = 0;
  74. static    int    Create_iv = 0;
  75. static    int    Create_cv = 0;
  76. static    int    NoInitialize = 0;
  77.     int    LineDirectives = 1;
  78. static    int    ExtraLineDirectives = 0;
  79. static    int    ForceGenerate = 0;
  80.  
  81.  
  82. objrtn    open_file(char *file,char *mode);
  83. char    *trunc_mname(char *mname);
  84.  
  85. static    void    add_generic(object generics, char *gname, object proto, int check);
  86. static    int need_to_make(object classes,object generics,char *file);
  87. static    void make_h(object classes,object generics,char *file, object argList, object inc_sh, object inc_ah);
  88. static    void make_c(object classes,object generics,char *file, object inc_sc, object inc_ac);
  89. static    void read_gens(object classes,object generics,char *file,object exceptions, int errorOK);
  90. static    void proc_gen_class(object classes,object fobj);
  91. static    void proc_gen_generic(object generics,object fobj,object exceptions);
  92. static    void read_docs(object classes,object generics,char *file);
  93. static    void proc_doc_cls(object classes,char *buf,char *word,object fobj);
  94. static    void proc_doc_gen(object generics,char *buf,char *word,object fobj);
  95. static    void process_line(char *to,char *from);
  96. static    void read_exceptions(object exceptions,char *file);
  97. static    void read_src(object classes,object generics,char *file,object exceptions);
  98. static    void src_class(object fobj,object classes, char *initmeth);
  99. static    int make_arg(object fobj,object args,int *old, int *vararg);
  100. static    int pp_make_arg(object fobj,object args,int *old, object ivars, object cvars, int *convert);
  101. static    objrtn make_arg_list(object fobj,int *old, int *vararg);
  102. static    objrtn pp_make_arg_list(object fobj,int *old, object ivars, object cvars, int convert);
  103. static    void src_method(object fobj,object methods,int vararg);
  104. static    void pp_method(object tkn, object fobj,object methods,object sgenerics, object sobj,char *mtype, int mclass, int vararg, object ivars, object cvars, object className);
  105. static    void pp_local_method(object  tkn, object fobj, object sobj, char *mtype, int mclass, object  ivars, object  cvars);
  106. static    void src_generic(object fobj,object sgenerics);
  107. static    void src_generic2(object fobj,object sgenerics);
  108. static    void addto_generics(object smethods,object sgenerics,object generics,object exceptions);
  109. static    void preprocess(object classes,object generics,char *file,object exceptions, int mkc);
  110. static    int valid_symbol(char *tkn);
  111. static    void pp_defclass(object tkn, object fobj,object className,object superClasses,object idecls,object cdecls,object ivars,object cvars,object init, object classes);
  112. static    void pp_decl_section(object tkn, char *p,object fobj,object idecls,object ivars, object ovars);
  113. static    int get_var(char *var,char *buf);
  114. /*static    void add_underscore(char *buf);*/
  115. static    void pp_init_section(object tkn, char *p,object fobj,object init);
  116. static    char *getword(char *s,char *w,char c);
  117. static    int get_line(object fobj,char *line);
  118. static    char *gettoken(object fobj);
  119. static    char *gettype(char *s,char *w);
  120. static    void compress(char *f);
  121. static  void pp_gen_head(object sobj, object className,object idecls,object cdecls,object ivars,object cvars, char *file);
  122. static    void pp_gen_initmethod(object  sobj,object superClasses,object  init,object  isgenerics,object  csgenerics,object ismethods, object csmethods, object  ivars,object  cvars, object className);
  123. static    void pp_body(char *p, object fobj,object sobj,int mclass, object tkn, int convert, object prototype);
  124. static  int touch(char *f);
  125. static    void    touch_all(object argList);
  126. static    void    copyright(object fobj);
  127. static    char    *file_extension(char *file);
  128. static    void    strip_extension(char *file);
  129. static    char    *new_ext(char *file, char *ext);
  130. static    int    class_source(char *p);
  131. static    void    pp_gen_iv(char *file,object className,object idecls);
  132. static    void    pp_gen_cv(char *file,object className,object cdecls);
  133.  
  134.  
  135. int    main(int argc, char **argv)
  136. {
  137.     object    classes;    /*  classes            */
  138.     object    generics;    /*  generic + prototype        */
  139.     object    exceptions;    /*  generics with no arg checking   */
  140.     object    argList;    /*  list of command line arguments  */
  141.     object    inc_sc=NULL;    /*  system files to include in generics.c  */
  142.     object    inc_ac=NULL;    /*  app files to include in generics.c  */
  143.     object    inc_sh=NULL;    /*  system files to include in generics.h  */
  144.     object    inc_ah=NULL;    /*  app files to include in generics.h  */
  145.     object    seq, arg;
  146.     char    *p;
  147.     int    g1, c1, g2, c2;
  148.     int    zero = 0, ignore = 0;
  149.  
  150.     InitDynace(&argc);
  151.  
  152. #ifdef    USE_GC
  153.     gSetMemoryBufferArea(Dynace, 100000L);
  154. #endif
  155.  
  156. /*    gObjectChecking(Dynace, 0);   */
  157.  
  158.     if (argc < 2)  {
  159.         vPrintf(stdoutStream, "DPP Version %s %s\n\n", __DATE__, __TIME__);
  160.         gPuts(stdoutStream, "dpp is Copyright (c) 1993-1996 Algorithms Corporation\n");
  161.         gPuts(stdoutStream, "       All rights reserved.\n\n");
  162.         gPuts(stdoutStream, "usage: dpp  options\n");
  163.         gPuts(stdoutStream, "\nValid options:\n\n");
  164.  
  165.         gPuts(stdoutStream, "\t-e file...\tread prototype exception file\n");
  166.         gPuts(stdoutStream, "\t-g [file]...\tread pre-existing generics (.h) files\n");
  167.         gPuts(stdoutStream, "\t\t\t(default generics.h)\n");
  168.         gPuts(stdoutStream, "\t-G [file]...\tread pre-existing generics (.h) files,\n");
  169.         gPuts(stdoutStream, "\t\t\tno error if missing (default generics.h)\n");
  170.         gPuts(stdoutStream, "\t-s file...\tread source (.c, .d) files\n");
  171. /*        gPuts(stdoutStream, "\t-d file...\tread class doc files (out-of-date feature)\n\n");   */
  172.  
  173.         gPuts(stdoutStream, "\t-h [file] \tcreate a class header (.h) file (default generics.h)\n");
  174.         gPuts(stdoutStream, "\t-c [file] \tcreate generics (.c) file (default generics.c)\n\n");
  175.  
  176.         gPuts(stdoutStream, "\t-p file...\tpreprocess .d file and create .c file\n\n");
  177.  
  178.         gPuts(stdoutStream, "\t-t [file]...\tfiles to be touched if header file is up-to-date\n");
  179. #ifdef    unix        
  180.         gPuts(stdoutStream, "\t\t\t(defaults to generics.h generics.c generics.o)\n\n");
  181. #else        
  182.         gPuts(stdoutStream, "\t\t\t(defaults to generics.h generics.c generics.obj)\n\n");
  183. #endif
  184.         gPuts(stdoutStream, "\t-N        \tforce no prototyping for any generics\n");
  185.         gPuts(stdoutStream, "\t-i        \tignore errors and produce output files\n");
  186.         gPuts(stdoutStream, "\t-iv       \tcreate external iv structure\n");
  187.         gPuts(stdoutStream, "\t-cv       \tcreate external cv structure\n");
  188.         gPuts(stdoutStream, "\t-ni       \tdon't generate initialization functions\n");
  189.         gPuts(stdoutStream, "\t-nld      \tdon't generate #line directives\n");
  190.         gPuts(stdoutStream, "\t-eld      \tgenerate extra #line directives\n");
  191.         gPuts(stdoutStream, "\t-Isc file...\tadd system include files to generics.c\n");
  192.         gPuts(stdoutStream, "\t-Iac file...\tadd application include files to generics.c\n");
  193.         gPuts(stdoutStream, "\t-Ish file...\tadd system include files to generics.h\n");
  194.         gPuts(stdoutStream, "\t-Iah file...\tadd application include files to generics.h\n");
  195.         gPuts(stdoutStream, "\t-q        \tquiet operation\n");
  196.         gPuts(stdoutStream, "\t-z        \talways return a 0 error code\n");
  197. #if 0
  198.         gPuts(stdoutStream, "\t-mp [txt] \tdefault method name prefix\n");
  199.         gPuts(stdoutStream, "\t-ms [txt] \tdefault method name suffix\n");
  200. #endif
  201.         gPuts(stdoutStream, "\t-nai      \tno auto include generation\n");
  202.         gPuts(stdoutStream, "\t-mg       \tmacro guard typedefs and inlines\n");
  203.         gPuts(stdoutStream, "\t-C        \tgenerate Algorithms copyright\n");
  204.         vPrintf(stdoutStream, "\t-Sn       \tgenerate code for strategy n (default %d)\n", Strategy);
  205.         gPuts(stdoutStream, "\t-X        \tallow C generic overloading\n");
  206.         gPuts(stdoutStream, "\t-F        \tuse fast-wide method cache\n");
  207.         gPuts(stdoutStream, "\t-f        \tforce creation of generics.h file\n");
  208.         gPuts(stdoutStream, "\n");
  209.  
  210.         exit(-1);
  211.     }
  212.  
  213.     argList = gNewArglist(ArgumentList, argc, argv);
  214.     gDeepDisposeFirst(argList);  /*  don't need command name  */
  215.  
  216.     classes     = gNewWithInt(Set, 201);
  217.     generics    = gNewWithInt(StringDictionary, 401);
  218.     exceptions  = gNewWithInt(Set, 201);
  219.  
  220.     for (seq=gSequence(argList), arg=gNext(seq) ; arg ; arg = gNext(seq)) {
  221.         p = gStringValue(arg);
  222.         if (*p == '-')
  223.             if (streq(p+1, "C"))
  224.                 Copyright = 1;
  225.             else if (streq(p+1, "k"))
  226.                 InKernel = 1;
  227.             else if (streq(p+1, "N"))
  228.                 NoProto = 1;
  229.             else if (streq(p+1, "i"))
  230.                 ignore = 1;
  231.             else if (streq(p+1, "q"))
  232.                 Quiet = 1;
  233.             else if (streq(p+1, "z"))
  234.                 zero = 1;
  235.             else if (streq(p+1, "X"))
  236.                 AllowOverloads = 1;
  237.             else if (streq(p+1, "nai"))
  238.                 GenIncludes = 0;
  239.             else if (streq(p+1, "mg"))
  240.                 MacroGuard = 1;
  241.             else if (streq(p+1, "F"))
  242.                 FastWideCache = 1;
  243.             else if (p[1] == 'S')
  244.                 Strategy = atoi(p+2);
  245.             else if (streq(p+1, "iv"))
  246.                 Create_iv = 1;
  247.             else if (streq(p+1, "cv"))
  248.                 Create_cv = 1;
  249.             else if (streq(p+1, "ni"))
  250.                 NoInitialize = 1;
  251.             else if (streq(p+1, "nld"))
  252.                 LineDirectives = 0;
  253.             else if (streq(p+1, "eld"))
  254.                 ExtraLineDirectives = 1;
  255.             else if (streq(p+1, "f"))
  256.                 ForceGenerate = 1;
  257.     }
  258.  
  259.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  260.         p = gStringValue(arg);
  261.         while (arg  &&  streq(p, "-e"))
  262.             for (arg=gNext(seq) ; arg ; arg=gNext(seq))  {
  263.                 p = gStringValue(arg);
  264.                 if (*p == '-')
  265.                     break;
  266.                 read_exceptions(exceptions, p);
  267.             }
  268.     }
  269.  
  270.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  271.         p = gStringValue(arg);
  272.         while (arg  &&  (streq(p, "-g")  ||  streq(p, "-G")))  {
  273.             int    errorOK;
  274.             errorOK = p[1] == 'G';
  275.             if (arg = gNext(seq))
  276.                 p = gStringValue(arg);
  277.             else
  278.                 p = "-";
  279.             if (*p == '-')
  280.                 read_gens(classes, generics, "generics.h", exceptions, errorOK);
  281.             for ( ; arg ; arg=gNext(seq))  {
  282.                 p = gStringValue(arg);
  283.                 if (*p == '-')
  284.                     break;
  285.                 read_gens(classes, generics, p, exceptions, errorOK);
  286.             }
  287.         }
  288.     }
  289.  
  290.     g1 = gSize(generics);
  291.     c1 = gSize(classes);
  292.  
  293.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  294.         p = gStringValue(arg);
  295.         while (arg  &&  streq(p, "-d"))
  296.             for (arg=gNext(seq) ; arg ; arg=gNext(seq))  {
  297.                 p = gStringValue(arg);
  298.                 if (*p == '-')
  299.                     break;
  300.                 read_docs(classes, generics, p);
  301.             }
  302.     }
  303.  
  304.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  305.         p = gStringValue(arg);
  306.         while (arg  &&  streq(p, "-s"))
  307.             for (arg=gNext(seq) ; arg ; arg=gNext(seq))  {
  308.                 p = gStringValue(arg);
  309.                 if (*p == '-')
  310.                     break;
  311.                 if (class_source(p))
  312.                     preprocess(classes, generics, p, exceptions, 0);
  313.                 else
  314.                     read_src(classes, generics, p, exceptions);
  315.             }
  316.     }
  317.  
  318.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  319.         p = gStringValue(arg);
  320.         while (arg  &&  streq(p, "-p"))
  321.             for (arg=gNext(seq) ; arg ; arg=gNext(seq))  {
  322.                 p = gStringValue(arg);
  323.                 if (*p == '-')
  324.                     break;
  325.                 preprocess(classes, generics, p, exceptions, 1);
  326.             }
  327.     }
  328.  
  329.     g2 = gSize(generics);
  330.     c2 = gSize(classes);
  331.  
  332.     if (ErrorCode  &&  !ignore)
  333.         goto end;
  334.  
  335.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  336.         p = gStringValue(arg);
  337.         while (arg  &&  streq(p, "-Isc"))  {
  338.             if (!inc_sc)
  339.                 inc_sc = gNew(LinkObject);
  340.             for (arg=gNext(seq) ; arg ; arg=gNext(seq))  {
  341.                 p = gStringValue(arg);
  342.                 if (*p == '-')
  343.                     break;
  344.                 gAddLast(inc_sc, gNewWithStr(String, p));
  345.             }
  346.         }
  347.     }
  348.  
  349.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  350.         p = gStringValue(arg);
  351.         while (arg  &&  streq(p, "-Iac"))  {
  352.             if (!inc_ac)
  353.                 inc_ac = gNew(LinkObject);
  354.             for (arg=gNext(seq) ; arg ; arg=gNext(seq))  {
  355.                 p = gStringValue(arg);
  356.                 if (*p == '-')
  357.                     break;
  358.                 gAddLast(inc_ac, gNewWithStr(String, p));
  359.             }
  360.         }
  361.     }
  362.  
  363.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  364.         p = gStringValue(arg);
  365.         while (arg  &&  streq(p, "-Ish"))  {
  366.             if (!inc_sh)
  367.                 inc_sh = gNew(LinkObject);
  368.             for (arg=gNext(seq) ; arg ; arg=gNext(seq))  {
  369.                 p = gStringValue(arg);
  370.                 if (*p == '-')
  371.                     break;
  372.                 gAddLast(inc_sh, gNewWithStr(String, p));
  373.             }
  374.         }
  375.     }
  376.  
  377.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  378.         p = gStringValue(arg);
  379.         while (arg  &&  streq(p, "-Iah"))  {
  380.             if (!inc_ah)
  381.                 inc_ah = gNew(LinkObject);
  382.             for (arg=gNext(seq) ; arg ; arg=gNext(seq))  {
  383.                 p = gStringValue(arg);
  384.                 if (*p == '-')
  385.                     break;
  386.                 gAddLast(inc_ah, gNewWithStr(String, p));
  387.             }
  388.         }
  389.     }
  390.  
  391.     for (seq=gSequence(argList) ; arg=gNext(seq) ; )  {
  392.         p = gStringValue(arg);
  393.         if (streq(p, "-h"))  {
  394.             if (arg = gNext(seq))
  395.                 p = gStringValue(arg);
  396.             if (arg  &&  *p != '-')
  397.                 make_h(classes, generics, p, argList, inc_sh, inc_ah);
  398.             else
  399.                 make_h(classes, generics, "generics.h", argList, inc_sh, inc_ah);
  400.             if (arg)
  401.                 seq = DISPOSE(seq);
  402.             break;
  403.         }
  404.     }
  405.  
  406.     for (seq=gSequence(argList) ; arg=gNext(seq) ; )  {
  407.         p = gStringValue(arg);
  408.         if (streq(p, "-c"))  {
  409.             if (arg = gNext(seq))
  410.                 p = gStringValue(arg);
  411.             if (arg  &&  *p != '-')
  412.                 make_c(classes, generics, p, inc_sc, inc_ac);
  413.             else
  414.                 make_c(classes, generics, "generics.c", inc_sc, inc_ac);
  415.             if (arg)
  416.                 seq = DISPOSE(seq);
  417.             break;
  418.         }
  419.     }
  420.  
  421.  
  422. /*
  423.     gPrint(exceptions, stdoutStream);
  424.     gPrint(classes, stdoutStream);
  425.     gPrint(generics, stdoutStream);
  426. */
  427.  
  428.  end:
  429.     argList = DEEPDISPOSE(argList);
  430.     classes = DEEPDISPOSE(classes);
  431.     generics = DEEPDISPOSE(generics);
  432.     exceptions = DEEPDISPOSE(exceptions);
  433.     if (inc_sc)
  434.         inc_sc = DEEPDISPOSE(inc_sc);
  435.     if (inc_ac)
  436.         inc_ac = DEEPDISPOSE(inc_ac);
  437.     if (inc_sh)
  438.         inc_sh = DEEPDISPOSE(inc_sh);
  439.     if (inc_ah)
  440.         inc_ah = DEEPDISPOSE(inc_ah);
  441. #ifdef    USE_GC
  442.     gGC(Dynace);
  443. #endif
  444.     if (!Quiet  &&  (!ErrorCode  ||  ignore))  {
  445.         vPrintf(stdoutStream, "\nClasses  = %d, %d, %d\n", c1, c2-c1, c2);
  446.         vPrintf(stdoutStream, "Generics = %d, %d, %d\n", g1, g2-g1, g2);
  447. #ifdef    USE_GC
  448.         vPrintf(stdoutStream, "Memory = %ld, %ld, %ld\n",
  449.             gMaxMemUsed(Dynace), gCurMemUsed(Dynace), gMaxAfterGC(Dynace));
  450. #endif
  451.     }
  452.     return zero ? 0 : ErrorCode;
  453. }
  454.  
  455. objrtn    open_file(char *file, char *mode)
  456. {
  457.     object    fobj;
  458.  
  459.     fobj = gOpenFile(File, file, mode);
  460.     if (fobj)  {
  461.         if (!Quiet)
  462.             vPrintf(stdoutStream, "Now %s %s\n",
  463.                 streq(mode, RMODE) ? "reading" : "writing",
  464.                 file);
  465.     }  else  {
  466.         ErrorCode = 1;
  467.         vPrintf(stdoutStream, "Can't open %s for %s\n", file, 
  468.             streq(mode, RMODE) ? "reading" : "writing");
  469.     }
  470.     return fobj;
  471. }
  472.  
  473. static    int
  474. need_to_make(object classes,
  475.          object generics,
  476.          char   *file)
  477. {
  478.     object    cls, gens, seq, elm, gobj;
  479.     int    diff = 0;
  480.  
  481.     cls  = gNewWithInt(Set, 201);
  482.     gens = gNewWithInt(StringDictionary, 401);
  483.  
  484.     read_gens(cls, gens, file, NULL, 2);
  485.  
  486.     if (gSize(cls) != gSize(classes)  ||  gSize(gens) != gSize(generics))
  487.         diff = 1;
  488.     if (!diff)
  489.         for (seq=gSequence(cls)  ;  elm=gNext(seq) ; )
  490.             if (!gFind(classes, elm))  {
  491.                 diff = 1;
  492.                 DISPOSE(seq);
  493.                 break;
  494.             }
  495.     if (!diff)
  496.         for (seq=gSequence(gens)  ;  elm=gNext(seq) ; ) 
  497.             if (!(gobj=gFindStr(generics, gStringKey(elm)))  ||
  498.                 !gMatchNoError(gValue(elm), gValue(gobj)))  {
  499.                 diff = 1;
  500.                 DISPOSE(seq);
  501.                 break;
  502.             }
  503.             
  504.     DEEPDISPOSE(cls);
  505.     DEEPDISPOSE(gens);
  506.     if (!diff  &&  !Quiet)
  507.         vPrintf(stdoutStream, "No need to make %s\n", file);
  508.     return diff;
  509. }
  510.  
  511. static    void    touch_all(object argList)
  512. {
  513.     object    seq, arg;
  514.     char    *p;
  515.  
  516.     for (arg=seq=gSequence(argList) ; arg  &&  (arg=gNext(seq)) ; )  {
  517.         p = gStringValue(arg);
  518.         while (arg  &&  streq(p, "-t"))  {
  519.             if (arg = gNext(seq))
  520.                 p = gStringValue(arg);
  521.             else
  522.                 p = "-";
  523.             if (*p == '-')  {
  524.                 touch("generics.h");
  525.                 touch("generics.c");
  526.                 touch("generics.o");
  527.                 touch("generics.obj");
  528.             }
  529.             for ( ; arg ; arg=gNext(seq))  {
  530.                 p = gStringValue(arg);
  531.                 if (*p == '-')
  532.                     break;
  533.                 touch(p);
  534.             }
  535.         }
  536.     }
  537. }
  538.  
  539. static    void    make_macro_name(char *to, char *from)
  540. {
  541.     char    *f;
  542.  
  543.     for (f=from ; *f ; f++)
  544.         if (*f == '/'  ||  *f == '\\')
  545.             from = f + 1;
  546.          
  547.     *to++ = '_';
  548.     for ( ; *from ; ++from)
  549.         if (isalnum(*from))
  550.             if (islower(*from))
  551.                 *to++ = toupper(*from);
  552.             else
  553.                 *to++ = *from;
  554.         else
  555.             *to++ = '_';
  556.     *to = '\0';
  557. }
  558.  
  559. static    char    *file_extension(char *file)
  560. {
  561.     char    *r = "";
  562.  
  563.     while (*file)
  564.         if (*file++ == '.')
  565.             r = file;
  566.     return r;
  567. }
  568.  
  569. static    void    strip_extension(char *file)
  570. {
  571.     char    *r;
  572.  
  573.     for (r=NULL ; *file ; ++file)
  574.         if (*file == '.')
  575.             r = file;
  576.         else if (*file == '/'  ||  *file == '\\')
  577.             r = NULL;
  578.     if (r)
  579.         *r = '\0';
  580. }
  581.  
  582. static    char    *new_ext(char *file, char *ext)
  583. {
  584.     static    char    fname[80];
  585.     strcpy(fname, file);
  586.     strip_extension(fname);
  587. #ifndef    unix
  588.     {
  589.         char    *p;
  590.         for (p=fname ; *p ; p++)
  591.             *p = tolower(*p);
  592.     }
  593. #endif
  594.     strcat(fname, ".");
  595.     strcat(fname, ext);
  596.     return fname;
  597. }
  598.  
  599. static    void    gen_inline(object fobj, char *name, object proto)
  600. {
  601.     char    *rtn;
  602.  
  603.     rtn = gStringValue(gReturnType(proto));
  604.     vPrintf(fobj, "inline\t%s\t%s(", rtn, name);
  605.     gPrintArgs(proto, fobj);
  606.     gPuts(fobj, ")\n{\n");
  607.     if (FastWideCache)
  608.         gPuts(fobj, "\tofun _meth_;\n");
  609.     if (gIsVarArg(proto))
  610.         vPrintf(fobj, "\tva_list _rest_;\n\tva_start(_rest_, %s);\n", gLastArg(proto));
  611.     if (FastWideCache)  {
  612.         vPrintf(fobj, "\tFW_GENERIC(%s);\n", name);
  613.         vPrintf(fobj, "\t%s (*(%s_t)_meth_)(",
  614.             streq(rtn, "void")?"":"return", name);
  615.     } else
  616.         vPrintf(fobj, "\t%s (*(%s_t)_FindMethod(self, Generic(%s)))(",
  617.             streq(rtn, "void")?"":"return", name, name);
  618.     gPrintVars(proto, fobj);
  619.     gPuts(fobj, ");\n}\n");
  620. }
  621.  
  622. static    void
  623. make_h(object    classes,
  624.        object    generics,
  625.        char    *file,
  626.        object    argList,
  627.        object    inc_sh,
  628.        object    inc_ah)
  629. {
  630.     object    fobj, seq, obj, proto;
  631.     char    macro[60], *name, *rtn;
  632.     
  633.     rtn = file_extension(file);
  634.     if (strne(rtn, "h")  &&
  635.         strne(rtn, "H")  &&
  636.         strne(rtn, "hh")  &&
  637.         strne(rtn, "HH"))  {
  638.         ErrorCode = 1;
  639.         vPrintf(stdoutStream, "Generated generic header file names must be valid C or C++ header file names.\n");
  640.         return;
  641.     }
  642.  
  643.     if (!ForceGenerate  &&  !need_to_make(classes, generics, file))  {
  644.         touch_all(argList);
  645.         return;
  646.     }
  647.  
  648.     if (NULL == (fobj = open_file(file, WMODE)))
  649.         return;
  650.  
  651.     if (Copyright)
  652.         copyright(fobj);
  653.  
  654. #ifndef    DBI
  655.     gPuts(fobj, "\n\n/*  This file is automatically generated by dpp and should not normally\n");
  656.     gPuts(fobj,     "    be edited by hand.  */\n\n\n");
  657.  
  658.     make_macro_name(macro, file);
  659.  
  660.     vPrintf(fobj, "#ifndef\t%s\n", macro);
  661.     vPrintf(fobj, "#define\t%s\n\n\n", macro);
  662.  
  663.     gPuts(fobj, "#ifdef\tDPP_STRATEGY\n");
  664.     vPrintf(fobj, "#if\tDPP_STRATEGY != %d\n", Strategy);
  665.     gPuts(fobj, "#error Incompatible DPP Strategies\n");
  666.     gPuts(fobj, "#endif\n");
  667.     gPuts(fobj, "#else\n");
  668.     vPrintf(fobj, "#define\tDPP_STRATEGY %d\n", Strategy);
  669.     gPuts(fobj, "#endif\n\n");
  670.  
  671.     gPuts(fobj, "#ifdef\tDPP_FASTWIDE\n");
  672.     vPrintf(fobj, "#if\tDPP_FASTWIDE != %d\n", FastWideCache);
  673.     gPuts(fobj, "#error Incompatible DPP FastWide Status\n");
  674.     gPuts(fobj, "#endif\n");
  675.     gPuts(fobj, "#else\n");
  676.     vPrintf(fobj, "#define\tDPP_FASTWIDE %d\n", FastWideCache);
  677.     gPuts(fobj, "#endif\n\n");
  678.  
  679.     if (inc_sh)  {
  680.         for (seq = gSequence(inc_sh) ; obj = gNext(seq) ; )
  681.             vPrintf(fobj, "#include <%s>\n", gStringValue(obj));
  682.         gPuts(fobj, "\n");
  683.     }
  684.  
  685. /*    if (GenIncludes)  */
  686.         gPuts(fobj, "#include \"dynl.h\"\n\n\n");
  687.  
  688.     if (inc_ah)  {
  689.         for (seq = gSequence(inc_ah) ; obj = gNext(seq) ; )
  690.             vPrintf(fobj, "#include \"%s\"\n", gStringValue(obj));
  691.         gPuts(fobj, "\n");
  692.     }
  693.     
  694.     gPuts(fobj, "#ifdef\t__cplusplus\n");
  695.     gPuts(fobj, "extern\t\"C\"  {\n");
  696.     gPuts(fobj, "#endif\n\n\n");
  697.  
  698.     gPuts(fobj, "\n\n#undef\tSTART_CLASSES\n\n");
  699.     for (seq = gSequence(classes) ; obj = gNext(seq) ; )
  700.         vPrintf(fobj, "extern\tobject\t%s_c;\n", gStringValue(obj));
  701.     gPuts(fobj, "\n#undef\tEND_CLASSES\n\n\n");
  702.  
  703.     for (seq = gSequence(classes) ; obj = gNext(seq) ; )
  704.         vPrintf(fobj, "extern\tobjrtn\t%s_initialize(void);\n", gStringValue(obj));
  705.     gPuts(fobj, "\n\n\n");
  706.  
  707.     for (seq = gSequence(classes) ; obj = gNext(seq) ; )  {
  708.         name = gStringValue(obj);
  709.         vPrintf(fobj, "#define\t%s\t(%s_c ? %s_c : %s_initialize())\n", name, name, name, name);
  710.     }
  711.     gPuts(fobj, "\n\n\n");
  712.  
  713.     for (seq = gSequence(classes) ; obj = gNext(seq) ; )
  714.         vPrintf(fobj, "typedef\tobject\t%s_t;\n", gStringValue(obj));
  715.     gPuts(fobj, "\n\n\n");
  716.     
  717.     for (seq = gSequence(generics) ; obj = gNext(seq) ; )
  718.         vPrintf(fobj, "extern\tobject\tGeneric(%s);\n",
  719.             gStringKey(obj));
  720.     gPuts(fobj, "\n\n");
  721.     
  722.     gPuts(fobj, "#undef\tSTART_PROTOTYPES\n\n");
  723. #else
  724.     USE(macro);
  725.     gPuts(fobj, "\n//--------------------   generics.h   --------------------\n\n");
  726. #endif
  727.     for (seq = gSequence(generics) ; obj = gNext(seq) ; )  {
  728.         char    td[60];
  729.         
  730.         proto = gValue(obj);
  731.         name = gStringKey(obj);
  732.         if (MacroGuard)  {
  733.             make_macro_name(td, name);
  734.             vPrintf(fobj, "#ifndef\t%s\n", td);
  735.             vPrintf(fobj, "#define\t%s\n", td);
  736.         }
  737.         vPrintf(fobj, "typedef\t%s\t(*%s_t)(", 
  738.             gStringValue(gReturnType(proto)), name);
  739.         gPrintArgs(proto, fobj);
  740.         gPuts(fobj, ");\n");
  741.         if (Strategy == 3  ||  Strategy == 4  &&  !gIsVarArg(proto))
  742.             gen_inline(fobj, name, proto);
  743.         if (MacroGuard)
  744.             gPuts(fobj, "#endif\n");
  745.     }
  746. #ifndef    DBI
  747.     gPuts(fobj, "\n\n#undef\tEND_PROTOTYPES\n\n");
  748.     
  749.     for (seq = gSequence(generics) ; obj = gNext(seq) ; )  {
  750.         name = gStringKey(obj);
  751.         proto = gValue(obj);
  752.         if (Strategy < 3)
  753.             vPrintf(fobj, "extern\t%s_t\t%s;\n", name, name);
  754.         else if (Strategy == 4 && gIsVarArg(proto))  {
  755.             rtn = gStringValue(gReturnType(proto));
  756.             vPrintf(fobj, "extern\t%s\t%s(", rtn, name);
  757.             gPrintArgs(proto, fobj);
  758.             gPuts(fobj, ");\n");
  759.         }
  760. /*
  761.         else    *  C++ inline  *
  762.             gen_inline(fobj, name, proto);
  763. */
  764.     }
  765.     gPuts(fobj, "\n\n\n");
  766.  
  767.     gPuts(fobj, "#ifdef\t__cplusplus\n");
  768.     gPuts(fobj, "}\n");
  769.     gPuts(fobj, "#endif\n\n\n");
  770.  
  771.     vPrintf(fobj, "#endif\t/*  %s  */\n\n\n", macro);
  772. #endif
  773.     
  774.     gDispose(fobj);
  775. }
  776.  
  777. static    void    make_c(object    classes,
  778.                object    generics,
  779.                char    *file,
  780.                object    inc_sc,
  781.                object    inc_ac)
  782. {
  783.     object    fobj, seq, obj, proto;
  784.     char    *name, *rtn;
  785.     
  786.     rtn = file_extension(file);
  787.     if (strne(rtn, "c")  &&
  788.         strne(rtn, "C")  &&
  789.         strne(rtn, "cc")  &&
  790.         strne(rtn, "CC")  &&
  791.         strne(rtn, "cpp")  &&
  792.         strne(rtn, "CPP"))  {
  793.         ErrorCode = 1;
  794.         vPrintf(stdoutStream, "Generated generics.c file names must be valid C or C++ source file names.\n");
  795.         return;
  796.     }
  797.  
  798.     if (NULL == (fobj = open_file(file, WMODE)))
  799.         return;
  800.  
  801.     if (Copyright)
  802.         copyright(fobj);
  803. #ifdef    DBI
  804.     gPuts(fobj, "\n//--------------------   generics.c   --------------------\n\n");
  805. #else
  806.     gPuts(fobj, "\n\n/*  This file is automatically generated by dpp and should not normally\n");
  807.     gPuts(fobj,     "    be edited by hand.  */\n\n\n");
  808.  
  809.     if (inc_sc)  {
  810.         for (seq = gSequence(inc_sc) ; obj = gNext(seq) ; )
  811.             vPrintf(fobj, "#include <%s>\n", gStringValue(obj));
  812.         gPuts(fobj, "\n");
  813.     }
  814.  
  815.     if (inc_ac)  {
  816.         for (seq = gSequence(inc_ac) ; obj = gNext(seq) ; )
  817.             vPrintf(fobj, "#include \"%s\"\n", gStringValue(obj));
  818.         gPuts(fobj, "\n");
  819.     }
  820.  
  821.     if (GenIncludes)
  822.         gPuts(fobj, "#include \"generics.h\"\n\n");
  823.  
  824.     gPuts(fobj, "#ifdef\tDPP_STRATEGY\n");
  825.     vPrintf(fobj, "#if\tDPP_STRATEGY != %d\n", Strategy);
  826.     gPuts(fobj, "#error Incompatible DPP Strategies\n");
  827.     gPuts(fobj, "#endif\n");
  828.     gPuts(fobj, "#else\n");
  829.     gPuts(fobj, "#error DPP_STRATEGY not set.\n");
  830.     gPuts(fobj, "#endif\n\n");
  831.  
  832.     gPuts(fobj, "#ifdef\tDPP_FASTWIDE\n");
  833.     vPrintf(fobj, "#if\tDPP_FASTWIDE != %d\n", FastWideCache);
  834.     gPuts(fobj, "#error Incompatible DPP FastWide Status\n");
  835.     gPuts(fobj, "#endif\n");
  836.     gPuts(fobj, "#else\n");
  837.     gPuts(fobj, "#error DPP_FASTWIDE not set.\n");
  838.     gPuts(fobj, "#endif\n\n");
  839.     
  840.     gPuts(fobj, "#ifdef\t__cplusplus\n");
  841.     gPuts(fobj, "extern\t\"C\"  {\n");
  842.     gPuts(fobj, "#endif\n\n\n");
  843.  
  844.     for (seq = gSequence(generics) ; obj = gNext(seq) ; )
  845.         vPrintf(fobj, "object\tGeneric(%s);\n",    gStringKey(obj));
  846.     gPuts(fobj, "\n\n\n");
  847.  
  848. #endif
  849.     if (Strategy < 3)  {
  850.         for (seq = gSequence(generics) ; obj = gNext(seq) ; )  {
  851.             name = gStringKey(obj);
  852.             proto = gValue(obj);
  853.             rtn = gStringValue(gReturnType(proto));
  854.             if (Strategy == 1)  {
  855.                 vPrintf(fobj, "IGTYPE\t%s\t_%s(", rtn, name);
  856.                 gPrintArgs(proto, fobj);
  857.                 vPrintf(fobj, ")\n{\n\tGenericBody(%s);\n}\n\n", name);
  858.             } else if (Strategy == 2)  {
  859.                 vPrintf(fobj, "static\t%s\t_%s(", rtn, name);
  860.                 gPrintArgs(proto, fobj);
  861.                 gPuts(fobj, ")\n{\n");
  862.                 if (FastWideCache)
  863.                     gPuts(fobj, "\tofun _meth_;\n");
  864.                 if (gIsVarArg(proto))
  865.                     vPrintf(fobj, "\tva_list _rest_;\n\tva_start(_rest_, %s);\n", gLastArg(proto));
  866.                 if (FastWideCache)  {
  867.                     vPrintf(fobj, "\tFW_GENERIC(%s);\n", name);
  868.                     vPrintf(fobj, "\t%s (*(%s_t)_meth_)(",
  869.                         streq(rtn, "void")?"":"return", name);
  870.                 } else
  871.                     vPrintf(fobj, "\t%s (*(%s_t)_FindMethod(self, Generic(%s)))(",
  872.                         streq(rtn, "void")?"":"return", name, name);
  873.                 gPrintVars(proto, fobj);
  874.                 gPuts(fobj, ");\n}\n\n");
  875.             }
  876.         }
  877. #ifndef    DBI
  878.         gPuts(fobj, "\n\n\n");
  879.     
  880.         for (seq = gSequence(generics) ; obj = gNext(seq) ; )  {
  881.             name = gStringKey(obj);
  882.             vPrintf(fobj, "%s_t\t%s = _%s;\n", name, name, name);
  883.         }
  884.         gPuts(fobj, "\n\n\n");
  885. #endif
  886.     }
  887.     
  888.     if (Strategy == 4)  {
  889.         for (seq = gSequence(generics) ; obj = gNext(seq) ; )
  890.             if (gIsVarArg(proto = gValue(obj)))  {
  891.                 name = gStringKey(obj);
  892.                 rtn = gStringValue(gReturnType(proto));
  893.                 vPrintf(fobj, "%s\t%s(", rtn, name);
  894.                 gPrintArgs(proto, fobj);
  895.                 gPuts(fobj, ")\n{\n");
  896.                 if (FastWideCache)
  897.                     gPuts(fobj, "\tofun _meth_;\n");
  898.                 vPrintf(fobj, "\tva_list _rest_;\n\tva_start(_rest_, %s);\n", gLastArg(proto));
  899.                 if (FastWideCache)  {
  900.                     vPrintf(fobj, "\tFW_GENERIC(%s);\n", name);
  901.                     vPrintf(fobj, "\t%s (*(%s_t)_meth_)(",
  902.                         streq(rtn, "void")?"":"return", name);
  903.                 } else
  904.                     vPrintf(fobj, "\t%s (*(%s_t)_FindMethod(self, Generic(%s)))(",
  905.                         streq(rtn, "void")?"":"return", name, name);
  906.                 gPrintVars(proto, fobj);
  907.                 gPuts(fobj, ");\n}\n\n");
  908.             }
  909.         gPuts(fobj, "\n\n\n");
  910.     }
  911. #ifndef    DBI
  912.     gPuts(fobj, "void\tInitGenerics()\n{\n");
  913.  
  914.     for (seq = gSequence(generics) ; obj = gNext(seq) ; )  {
  915.         char    *gn;
  916.         gn = gStringKey(obj);
  917.         /*  don't init generics which have already been initialized by
  918.             the kernel!   */
  919.         if (strne(gn, "gNew")  &&
  920.             strne(gn, "gNewClass")  &&
  921.             strne(gn, "gNewMethod")  &&
  922.             strne(gn, "gNewWithStr"))
  923.             vPrintf(fobj, "\tInitGeneric( %s );\n", gn);
  924.     }
  925.     gPuts(fobj, "}\n\n\n");
  926.     
  927.     gPuts(fobj, "void\tInitDynace(void *s)\n");
  928.     gPuts(fobj, "{\n");
  929.     vPrintf(fobj, "\tint\tnClasses = %d;\n\n", gSize(classes));
  930.  
  931.     /*  use *2 since we must account for metaclasses  */
  932.     gPuts(fobj, "\n\tInitKernel(s, nClasses*2);\n\n");
  933.     
  934.     gPuts(fobj, "}\n\n\n");
  935.     
  936.     gPuts(fobj, "#ifdef\t__cplusplus\n");
  937.     gPuts(fobj, "}\n");
  938.     gPuts(fobj, "#endif\n\n\n");
  939. #endif
  940.     gDispose(fobj);
  941. }
  942.  
  943. static    void
  944. read_gens(object    classes,
  945.       object    generics,
  946.       char        *file,
  947.       object    exceptions,
  948.       int        errorOK)   /*  0=pass on errors,  1=open error ok,
  949.                        2=all errors ok  */
  950. {
  951.     object    fobj;
  952.     char    *tkn;
  953.     int    save = ErrorCode;
  954.     
  955.     if (NULL == (fobj = open_file(file, RMODE)))  {
  956.         if (errorOK)
  957.             ErrorCode = save;
  958.         return;
  959.     }
  960.  
  961.     gettoken(NULL);  /*  reset state info  */
  962. /*    SeeCode = 0;    */ /*  don't see between braces   */
  963.     SeeCode = 1;    /*  C++ has { in linkage directive  */
  964.     while ((tkn = gettoken(fobj))  &&  strne(tkn, "START_CLASSES"));
  965.     while ((tkn = gettoken(fobj))  &&  strne(tkn, "END_CLASSES"))
  966.         if (streq(tkn, "extern"))
  967.             proc_gen_class(classes, fobj);
  968.     while ((tkn = gettoken(fobj))  &&  strne(tkn, "START_PROTOTYPES"));
  969.     while ((tkn = gettoken(fobj))  &&  strne(tkn, "END_PROTOTYPES"))
  970.         if (streq(tkn, "typedef"))
  971.             proc_gen_generic(generics, fobj, exceptions);
  972.     gDispose(fobj);
  973.     if (errorOK == 2)
  974.         ErrorCode = save;
  975. }
  976.  
  977. static    void    proc_gen_class(object classes, object fobj)
  978. {
  979.     object    cn, res;
  980.     char    *tkn;
  981.     
  982.     tkn = gettoken(fobj);
  983.     if (!tkn  ||  strne(tkn, "object"))
  984.         return;
  985.     tkn = gettoken(fobj);
  986.     if (!tkn)
  987.         return;
  988.     cn = gNewWithStr(String, tkn);
  989.     gDrop(cn, -2);  /*  remove trailing _c  */
  990.     res = gAdd(classes, cn);
  991.     if (!res)
  992.         DISPOSE(cn);
  993. }
  994.  
  995. static    void    proc_gen_generic(object generics, object fobj, object exceptions)
  996. {
  997.     object    rtn, gen, args=NULL, proto;
  998.     char    *tkn, buf[200], *gname;
  999.     int    old, exception, vararg;
  1000.     
  1001.     *buf = '\0';
  1002.     while ((tkn = gettoken(fobj))  &&  *tkn != '(')  {
  1003.         if (*buf)
  1004.             strcat(buf, " ");
  1005.         strcat(buf, tkn);
  1006.     }
  1007.     rtn = gNewWithStr(String, buf);
  1008.  
  1009.     if (!(tkn = gettoken(fobj))  ||  *tkn != '*')  {
  1010.         DISPOSE(rtn);
  1011.         return;
  1012.     }
  1013.  
  1014.     if (!(tkn = gettoken(fobj))  ||  !istart(*tkn))  {
  1015.         DISPOSE(rtn);
  1016.         return;
  1017.     }
  1018.     gen = gNewWithStr(String, tkn);
  1019.     gDrop(gen, -2);    /*  get rid of trailing _t  */
  1020.  
  1021.     if (!(tkn = gettoken(fobj))  ||  *tkn != ')')  {
  1022.         DISPOSE(rtn);
  1023.         DISPOSE(gen);
  1024.         return;
  1025.     }
  1026.  
  1027.     if (!(tkn = gettoken(fobj))  ||  *tkn != '(')  {
  1028.         DISPOSE(rtn);
  1029.         DISPOSE(gen);
  1030.         return;
  1031.     }
  1032.     gname = gStringValue(gen);
  1033.     if (!gFindStr(generics, gname))  {
  1034.         exception = NoProto || exceptions  &&  gFind(exceptions, gen);
  1035.         if (!exception)
  1036.             args = make_arg_list(fobj, &old, &vararg);
  1037.         proto = gNewWithStrStr(Prototype, gname, gStringValue(rtn));
  1038.         if (!exception)  {
  1039.             gSetArgs(proto, args);
  1040.             if (vararg)
  1041.                 gVarArg(proto);
  1042.         } else
  1043.             gException(proto);
  1044.         add_generic(generics, gname, proto, 0);
  1045.     }
  1046.     DISPOSE(rtn);
  1047.     DISPOSE(gen);
  1048. }
  1049.  
  1050. static    void    add_generic(object generics, char *gname, object proto, int check)
  1051. {
  1052.     char    buf[80];
  1053.  
  1054.     if (check)
  1055.         if (gname[0] == 'g'  &&  isupper(gname[1]))  {
  1056.             strcpy(buf, gname);
  1057.             *buf = 'v';
  1058.             if (gFindStr(generics, buf))  {
  1059.                 vPrintf(stdoutStream, "Warning: Both generics %s and %s exist.\n", gname, buf);
  1060.     /*            ErrorCode = 1;   */
  1061.             }
  1062.         } else if (gname[0] == 'v'  &&  isupper(gname[1]))  {
  1063.             strcpy(buf, gname);
  1064.             *buf = 'g';
  1065.             if (gFindStr(generics, buf))  {
  1066.                 vPrintf(stdoutStream, "Warning: Both generics %s and %s exist.\n", gname, buf);
  1067.     /*            ErrorCode = 1;   */
  1068.             }
  1069.         }
  1070.     gAddStr(generics, gname, proto);
  1071. }
  1072.  
  1073. static    void    read_docs(object classes, object generics, char *file)
  1074. {
  1075.     object    fobj;
  1076.     char    buf[BUFSIZE], word[MAXWORDSZ+1], *next;
  1077.     
  1078.     if (NULL == (fobj = open_file(file, RMODE)))
  1079.         return;
  1080.  
  1081.     while (gGets(fobj, buf, BUFSIZE))  {
  1082.         for (next=buf ; isspace(*next) ; ++next);
  1083.         if (!*next  ||  *next == ';')
  1084.             continue;
  1085.         if (!(next = getword(next, word, '\0')))
  1086.             continue;
  1087.         if (streq(word, "Classes:"))
  1088.             proc_doc_cls(classes, buf, word, fobj);
  1089.         if (streq(word, "Class:"))
  1090.             proc_doc_gen(generics, buf, word, fobj);
  1091.     }
  1092.     gDispose(fobj);
  1093. }
  1094.  
  1095. static    void    proc_doc_cls(object classes, char *buf, char *word, object fobj)
  1096. {
  1097.     char    *next;
  1098.     object    cn;
  1099.     
  1100.     while (gGets(fobj, buf, BUFSIZE))  {
  1101.         for (next=buf ; isspace(*next) ; ++next);
  1102.         if (!*next  ||  *next == ';')
  1103.             continue;
  1104.         if (!(next = getword(next, word, '\0')))
  1105.             continue;
  1106.         if (streq(word, "Class:"))
  1107.             return;
  1108.         cn = gNewWithStr(String, word);
  1109.         if (!gAdd(classes, cn))
  1110.             DISPOSE(cn);
  1111.     }
  1112. }
  1113.  
  1114. static    void proc_doc_gen(object generics, char *buf, char *word, object fobj)
  1115. {
  1116.     char    *next, *p;
  1117.     object    type, proto;
  1118.     
  1119.     while (gGets(fobj, buf, BUFSIZE))  {
  1120.         for (next=buf ; isspace(*next) ; ++next);
  1121.         if (!*next  ||  *next == ';')
  1122.             continue;
  1123.         for (p=next ; *p ; ++p)
  1124.             if (*p == ':')
  1125.                 continue;
  1126.         if (!(next = gettype(next, word)))
  1127.             continue;
  1128.         type = gNewWithStr(String, word);
  1129.         next = getword(next, word, '\0');
  1130.         if (!next)  {
  1131.             DISPOSE(type);
  1132.             continue;
  1133.         }
  1134.         if (!gFindStr(generics, word))  {
  1135.             proto = gNewWithStrStr(Prototype, word, gStringValue(type));
  1136.             gVarArg(proto);
  1137.             add_generic(generics, word, proto, 1);
  1138.         }
  1139.         DISPOSE(type);
  1140.     }
  1141. }
  1142.  
  1143. #define CODE_STATE    0    /*  in normal C code        */
  1144. #define COMMENT_STATE    1    /*  in comment            */
  1145. #define QUOTE_STATE    2    /*  in quoted string        */
  1146.  
  1147. /*  This function copies FROM to TO without comments, strings or
  1148.     code between braces.  */
  1149.  
  1150. static    void    process_line(char *to, char *from)
  1151. {
  1152.     static    int    state;
  1153.     static    int    bracelevel;
  1154.     
  1155.     if (!to)  {  /*  reset state  */
  1156.         state = CODE_STATE;
  1157.         bracelevel = 0;
  1158.         return;
  1159.     }
  1160.     
  1161.     while (*from)
  1162.         switch (state)  {
  1163.         case CODE_STATE:
  1164. #if 0
  1165.             if (*from == '"')  {
  1166.                 state = QUOTE_STATE;
  1167.                 if (!bracelevel  ||  SeeCode)
  1168.                     *to++ = ' '; /* replace string with space */
  1169.             } else
  1170. #endif
  1171.             if (from[0] == '/'  &&  from[1] == '*')  {
  1172.                 state = COMMENT_STATE;
  1173.                 from += 2;
  1174.                 if (!bracelevel  ||  SeeCode)
  1175.                     *to++ = ' '; /* replace comment with space */
  1176.             } else if (from[0] == '/'  &&  from[1] == '/')
  1177.                 goto end;
  1178.             else if (*from == '\''  ||  *from == '"')  {
  1179.                 char    type = *from;
  1180.                 *to++ = *from++;
  1181.                 for ( ; *from  &&  *from != type ; ++from)  {
  1182.                     *to++ = *from;
  1183.                     if (*from == '\\'  &&  from[1])
  1184.                         *to++ = *++from;
  1185.                 }
  1186.                 if (*from)
  1187.                     *to++ = *from++;
  1188.             } else if (*from == '{')  {
  1189.                 if (!bracelevel++  ||  SeeCode)
  1190.                     *to++ = *from;
  1191.                 from++;
  1192.             } else if (*from == '}')  {
  1193.                 if (bracelevel)  {
  1194.                     if (!--bracelevel  ||  SeeCode)
  1195.                         *to++ = *from;
  1196.                 } else if (SeeCode)
  1197.                     *to++ = *from;
  1198.                 from++;
  1199.             } else if (!bracelevel  ||  SeeCode)
  1200.                 *to++ = *from++;
  1201.             else
  1202.                 from++;
  1203.             break;
  1204.         case COMMENT_STATE:
  1205.             if (from[0] == '*'  &&  from[1] == '/')  {
  1206.                 state = CODE_STATE;
  1207.                 from += 2;
  1208.             } else
  1209.                 from++;
  1210.             break;
  1211. #if 0
  1212.         case QUOTE_STATE:
  1213.             if (from[0] == '\\'  &&  from[1])
  1214.                 from++;
  1215.             else if (*from == '"')
  1216.                 state = CODE_STATE;
  1217.             break;
  1218. #endif
  1219.         }
  1220.  end:
  1221.     *to = '\0';
  1222. }
  1223.  
  1224. static    void    read_exceptions(object exceptions, char *file)
  1225. {
  1226.     object    fobj, gen;
  1227.     char    *tkn;        /*  token                */
  1228.     
  1229.     if (NULL == (fobj = open_file(file, RMODE)))
  1230.         return;
  1231.  
  1232.     gettoken(NULL);  /*  reset state info  */
  1233.     SeeCode = 0;    /*  don't see between braces  */
  1234.     while (tkn=gettoken(fobj))
  1235.         if (istart(*tkn))  {
  1236.             gen = gNewWithStr(String, tkn);
  1237.             if (!gAdd(exceptions, gen))
  1238.                 DISPOSE(gen);
  1239.         }
  1240.     gDispose(fobj);
  1241. }
  1242.  
  1243. static    void
  1244. read_src(object classes,
  1245.      object generics,
  1246.      char *file,
  1247.      object exceptions)
  1248. {
  1249.     object    fobj;
  1250.     char    *tkn;        /*  token                */
  1251.     object    ismethods;    /*  instance method + method prototype     */
  1252.     object    isgenerics;    /*  instance generic + method        */
  1253.     object    csmethods;    /*  class method + method prototype      */
  1254.     object    csgenerics;    /*  class generic + method        */
  1255.     char    initmeth[80];    /*  init method name            */
  1256.     
  1257.     if (NULL == (fobj = open_file(file, RMODE)))
  1258.         return;
  1259.     if (InKernel)
  1260.         strcpy(initmeth, "InitKernel");
  1261.     else
  1262.         *initmeth = '\0';
  1263.     gettoken(NULL);  /*  reset state info  */
  1264.     SeeCode = 0;    /*  don't see between braces until InitMethod  */
  1265.     isgenerics = gNewWithInt(StringDictionary, 301);
  1266.     ismethods  = gNewWithInt(StringDictionary, 301);
  1267.     csgenerics = gNewWithInt(StringDictionary, 301);
  1268.     csmethods  = gNewWithInt(StringDictionary, 301);
  1269.     while (tkn=gettoken(fobj))  {
  1270.         if (*tkn == '#')
  1271.             src_class(fobj, classes, initmeth);
  1272.         else if (streq(tkn, "imeth"))
  1273.             src_method(fobj, ismethods, 0);
  1274.         else if (streq(tkn, "ivmeth"))
  1275.             src_method(fobj, ismethods, 1);
  1276.         else if (streq(tkn, "cmeth"))
  1277.             src_method(fobj, csmethods, 0);
  1278.         else if (streq(tkn, "cvmeth"))
  1279.             src_method(fobj, csmethods, 1);
  1280.         else if (streq(tkn, "iMethod"))
  1281.             src_generic(fobj, isgenerics);
  1282.         else if (streq(tkn, "cMethod"))
  1283.             src_generic(fobj, csgenerics);
  1284.         else if (streq(tkn, "iMethodFor"))
  1285.             src_generic2(fobj, isgenerics);
  1286.         else if (streq(tkn, "cMethodFor"))
  1287.             src_generic2(fobj, csgenerics);
  1288.         else if (*initmeth  &&  streq(tkn, initmeth))
  1289.             SeeCode = 1;
  1290.     }
  1291.     gDispose(fobj);
  1292.     addto_generics(ismethods, isgenerics, generics, exceptions);
  1293.     addto_generics(csmethods, csgenerics, generics, exceptions);
  1294.     DEEPDISPOSE(ismethods);
  1295.     DEEPDISPOSE(isgenerics);
  1296.     DEEPDISPOSE(csmethods);
  1297.     DEEPDISPOSE(csgenerics);
  1298. }
  1299.  
  1300. static    void    src_class(object fobj, object classes, char *initmeth)
  1301. {
  1302.     object    cn, res;
  1303.     char    *tkn;
  1304.  
  1305.     tkn = gettoken(fobj);
  1306.     if (!tkn  ||  strne(tkn, "define"))  {
  1307.         gettoken(NULL);   /*  reset buffer - ignore line remainder  */
  1308.         return;
  1309.     }
  1310.     
  1311.     tkn = gettoken(fobj);
  1312.     if (!tkn  ||  strne(tkn, "CLASS"))  {
  1313.         gettoken(NULL);   /*  reset buffer - ignore line remainder  */
  1314.         return;
  1315.     }
  1316.     
  1317.     tkn = gettoken(fobj);
  1318.     if (!tkn  ||  !istart(*tkn))  {
  1319.         gettoken(NULL);   /*  reset buffer - ignore line remainder  */
  1320.         return;
  1321.     }
  1322.     cn = gNewWithStr(String, tkn);
  1323.     gDrop(cn, -2);  /*  get rid of trailing _c  */
  1324.     tkn = gStringValue(cn);
  1325.     sprintf(initmeth, "%s_initialize", tkn);
  1326.     res = gAdd(classes, cn);
  1327.     if (!res)  {
  1328.         ErrorCode = 1;
  1329.         vPrintf(stdoutStream, "Class %s has been previously defined.\n", tkn);
  1330.         DISPOSE(cn);
  1331.     }
  1332.     gettoken(NULL);   /*  reset buffer - ignore line remainder  */
  1333. }
  1334.  
  1335. static    int
  1336. make_arg(object    fobj,
  1337.      object args,
  1338.      int    *old,       /*  old K&R style function delclarations      */
  1339.      int    *vararg)    /*  set to 1 if fun is vararg        */
  1340. {
  1341.     char    buf[256], *tkn;
  1342.     int    paren = 0;    /*  paren level      */
  1343.     int    n = 0;        /*  number of tokens    */
  1344.     int    len;
  1345.  
  1346.     *buf = '\0';
  1347.     while ((tkn = gettoken(fobj))  &&  (len=strlen(buf)) < 200)  {
  1348.         if (!paren  &&  (*tkn == ')'  ||  *tkn == ','))
  1349.             break;
  1350.         if (*tkn == '(')  {
  1351.             if (len  &&  irest(buf[len-1]))
  1352.                 strcat(buf, " (");
  1353.             else
  1354.                 strcat(buf, "(");
  1355.             paren++;
  1356.         } else if (*tkn == ')')  {
  1357.             strcat(buf, ")");
  1358.             if (paren)
  1359.                 paren--;
  1360.         }  else  {
  1361.             if (*buf  &&  irest(buf[len-1]))
  1362.                 strcat(buf, " ");
  1363.             strcat(buf, tkn);
  1364.             if (streq(tkn, "..."))  {
  1365.                 n++;  /*  be sure not to think old style
  1366.                       because only one element  */
  1367.                 *vararg = 1;
  1368.             }
  1369.             n++;
  1370.         }
  1371.     }
  1372.     if (!*buf)
  1373.         return 0;
  1374.     if (n <= 1)
  1375.         *old = 1;
  1376.     gAddLast(args, gNewWithStr(String, buf));
  1377.     return tkn  &&  *tkn != ')';
  1378. }
  1379.  
  1380. #define    OUT_COMMA                    \
  1381.     if (!comma)  {                    \
  1382.         gPut(sobj, gNewToken(Token, ",", 0L, 1));    \
  1383.         comma = 1;                \
  1384.     }
  1385.  
  1386.  
  1387. static    int
  1388. pp_make_arg(object    fobj,
  1389.         object    args,
  1390.         int        *old,      /*  old K&R style function delclarations  */
  1391.         object    ivars,
  1392.         object    cvars,
  1393.         int        *convert)   /*  1=convert fixed args to varargs  */
  1394. {
  1395.     char    buf[256], *p=NULL;
  1396.     int    paren = 0;    /*  paren level      */
  1397.     int    n = 0;        /*  number of tokens    */
  1398.     int    len, more;
  1399.     object    tkn, ptkn=NULL;
  1400.  
  1401.     *buf = '\0';
  1402.     while (1)  {
  1403.         if (tkn = gNextToken(fobj))
  1404.             p = gStringValue(tkn);
  1405.         if (!tkn  ||  (len=strlen(buf)) > 200)
  1406.             break;
  1407.         if (!paren  &&  (*p == ')'  ||  *p == ','))
  1408.             break;
  1409.         n++;
  1410.         if (*p == '(')  {
  1411.             if (len  &&  irest(buf[len-1]))
  1412.                 strcat(buf, " (");
  1413.             else
  1414.                 strcat(buf, "(");
  1415.             paren++;
  1416.         } else if (*p == ')')  {
  1417.             strcat(buf, ")");
  1418.             if (paren)
  1419.                 paren--;
  1420.         }  else  {
  1421.             if (*buf  &&  irest(buf[len-1]))
  1422.                 strcat(buf, " ");
  1423.             strcat(buf, p);
  1424.             if (istart(*p))  {
  1425.                 object    sym = gToken(tkn);
  1426.                 if (gFind(ivars, sym)  ||  gFind(cvars, sym)) {
  1427.                     ErrorCode = 1;
  1428.                     vPrintf(stdoutStream, "Argument var and instance/class var with same name - line %ld\n", gLineNumber(tkn));
  1429.                 }
  1430.             }
  1431.             if (streq(p, "...")) 
  1432.                 n++;  /*  be sure not to think old style
  1433.                       because only one element  */
  1434.         }
  1435.         if (ptkn)
  1436.             if (n == 2  &&  streq(p, "self"))  {
  1437.                 n = 0;            /*  eat it  */
  1438.                 *buf = '\0';
  1439.                 ptkn = DISPOSE(ptkn);
  1440.                 DISPOSE(tkn);
  1441.             } else {
  1442.                 DISPOSE(ptkn);
  1443.                 ptkn = tkn;
  1444.             }
  1445.         else
  1446.             ptkn = tkn;
  1447.     }
  1448.     if (ptkn)  {
  1449.         char    *t = gStringValue(ptkn);
  1450.         if (n == 1  &&  streq("self", t))  {
  1451.             *buf = '\0';        /*  eat it  */
  1452.             n = 0;
  1453.             DISPOSE(ptkn);
  1454.         } else if (Strategy != 1  &&  streq(t, "..."))  {
  1455.             *convert = 1;
  1456.             DISPOSE(ptkn);
  1457.         } else
  1458.             DISPOSE(ptkn);
  1459.     }
  1460.     more = tkn  &&  *p != ')';
  1461.     if (tkn)
  1462.         tkn = DISPOSE(tkn);
  1463.  
  1464.     if (!*buf)
  1465.         return more;
  1466.     if (n <= 1)
  1467.         *old = 1;
  1468.     if (n == 1)
  1469.         gAddLast(args, vSprintf(String, "object %s", buf));
  1470.     else
  1471.         gAddLast(args, gNewWithStr(String, buf));
  1472.     return more;
  1473. }
  1474.  
  1475. static    objrtn    make_arg_list(object fobj, int *old, int *vararg)
  1476. {
  1477.     object    args;
  1478.     int    n = 0, va=0;
  1479.  
  1480.     *vararg = *old = 0;
  1481.     args = gNew(LinkObject);
  1482.     while (make_arg(fobj, args, old, &va))  {
  1483.         if (n++ == 1  &&  va)
  1484.             *vararg = 1;
  1485.         va = 0;
  1486.     }
  1487.     return args;
  1488. }
  1489.  
  1490. static    objrtn
  1491. pp_make_arg_list(object    fobj,
  1492.          int    *old,
  1493.          object ivars,
  1494.          object cvars,
  1495.          int    convert)  /*  1=convert fixed args to varargs  */
  1496. {
  1497.     object    args;
  1498.  
  1499.     *old = 0;
  1500.     args = gNew(LinkObject);
  1501.     gAddLast(args, gNewWithStr(String, "object self"));  /*  always first arg  */
  1502.     while (pp_make_arg(fobj, args, old, ivars, cvars, &convert));
  1503.     return args;
  1504. }
  1505.  
  1506. static    void    src_method(object fobj, object methods, int vararg)
  1507. {
  1508.     char    type[256], mname[MAXWORDSZ+1], *tkn;
  1509.     object    prototype, args;
  1510.     int    old, va;
  1511.  
  1512.     *type = *mname = '\0';
  1513.     while (tkn = gettoken(fobj))  {
  1514.         if (*tkn == '(')  {
  1515.             if (!gFindStr(methods, mname))  {
  1516.                 prototype = gNewWithStrStr(Prototype, mname, type);
  1517.                 args = make_arg_list(fobj, &old, &va);
  1518.                 if (!old)
  1519.                     gSetArgs(prototype, args);
  1520.                 else
  1521.                     DEEPDISPOSE(args);
  1522.                 if (vararg)
  1523.                     gVarArg(prototype);
  1524.                 tkn = gettoken(fobj);
  1525.                 if (tkn  &&  *tkn != ','  &&  *tkn != ';')
  1526.                     gAddStr(methods, mname, prototype);
  1527.                 else
  1528.                     DEEPDISPOSE(prototype);  /* it was a declaration  */
  1529.             }
  1530.             return;
  1531.         }
  1532.  
  1533.         if (*type)
  1534.             strcat(type, " ");
  1535.         if (streq(mname, "object"))
  1536.             strcat(type, "objrtn");
  1537.         else
  1538.             strcat(type, mname);
  1539.         strcpy(mname, tkn);
  1540.     }
  1541. }
  1542.  
  1543. static    void    method_syntax(object tkn, object generics, object olgens)
  1544. {
  1545.     if (tkn)  {
  1546.         vPrintf(stdoutStream, "Error: Bad method declaration syntax on line %ld\n", gLineNumber(tkn));
  1547.         DISPOSE(tkn);
  1548.     } else
  1549.         vPrintf(stdoutStream, "Error: Bad method declaration syntax\n");
  1550.     if (generics)
  1551.         DEEPDISPOSE(generics);
  1552.     if (olgens)
  1553.         DEEPDISPOSE(olgens);
  1554.     ErrorCode = 1;
  1555. }
  1556.  
  1557. static    objrtn    get_olname(object fobj, object tkn, char **pp)
  1558. {
  1559.     object    tt;
  1560.     char    *p;
  1561.     
  1562.     DISPOSE(tkn);
  1563.     tkn = gNextToken(fobj);
  1564.     if (!tkn)
  1565.         return NULL;
  1566.     p = gStringValue(tkn);
  1567.     if (!istart(*p))
  1568.         return DISPOSE(tkn);
  1569.     *pp = p;
  1570.     tt = gNextToken(fobj);
  1571.     if (!tt)
  1572.         return DISPOSE(tkn);
  1573.     p = gStringValue(tt);
  1574.     if (p[0] != '>'  ||  p[1])
  1575.         tkn = DISPOSE(tkn);
  1576.     DISPOSE(tt);
  1577.     return tkn;
  1578. }
  1579.  
  1580. static    void
  1581. generate_fixed_arg_meth(char         *olmname,
  1582.             char         *mname,
  1583.             object        prototype,
  1584.             int        mclass,
  1585.             object        sobj)
  1586. {
  1587.     char    *rtn;
  1588.     
  1589.     if (!prototype)
  1590.         return;
  1591.     if (mclass != 1)
  1592.         gFlush(sobj);
  1593.     gTLineDirective(sobj);
  1594.     vPrintf(sobj, "\nstatic\t%s\t%s(",
  1595.         rtn = gStringValue(gReturnType(prototype)),
  1596.         olmname);
  1597.     gPrintFixedArgs(prototype, sobj);
  1598.     gPuts(sobj, ")\n{\n");
  1599.     gPuts(sobj, "\tva_list\t_rest_;\n");
  1600.     gPuts(sobj, "\tva_start(_rest_, ");
  1601.     vPrintf(sobj, "%s);\n", gLastArg(prototype));
  1602. /*    gUseVars(prototype, sobj);  */
  1603.     if (streq(rtn, "void"))
  1604.         vPrintf(sobj, "\t%s(", mname);
  1605.     else
  1606.         vPrintf(sobj, "\treturn %s(", mname);
  1607.     gPrintVars(prototype, sobj);
  1608.     gPuts(sobj, ");\n");
  1609.     gPuts(sobj, "}\n\n");
  1610. }
  1611.  
  1612. static    void
  1613. generate_fixed_arg_vmeth(char         *olmname,
  1614.              char         *mname,
  1615.              object        prototype,
  1616.              int        mclass,
  1617.              object        sobj)
  1618. {
  1619.     char    *rtn;
  1620.     
  1621.     if (!prototype)
  1622.         return;
  1623.     if (mclass != 1)
  1624.         gFlush(sobj);
  1625.     gTLineDirective(sobj);
  1626.  
  1627.     vPrintf(sobj, "\nstatic\t%s\t%s(object self, ...)\n{\n",
  1628.         rtn = gStringValue(gReturnType(prototype)),
  1629.         olmname);
  1630.     gPuts(sobj, "\tva_list\t_rest_;\n");
  1631.     gPuts(sobj, "\tva_start(_rest_, self);\n");
  1632.     if (streq(rtn, "void"))
  1633.         vPrintf(sobj, "\t%s(", mname);
  1634.     else
  1635.         vPrintf(sobj, "\treturn %s(", mname);
  1636.     gPuts(sobj, "self, _rest_);\n}\n\n");
  1637. }
  1638.  
  1639. static    void
  1640. generate_fixed_arg_vmeth2(char         *olmname,
  1641.              char         *mname,
  1642.              object        prototype,
  1643.              int        mclass,
  1644.              object        sobj)
  1645. {
  1646.     char    *rtn, *t;
  1647.     object    pvar, vvar, pseq, vseq, pnxt, vnxt;
  1648.     int    i=0;
  1649.     
  1650.     if (!prototype  ||  !(pvar = gPrototype(prototype)))
  1651.         return;
  1652.     if (!(vvar = gParameters(prototype)))
  1653.         return;
  1654.     pseq = gSequence(pvar);
  1655.     vseq = gSequence(vvar);
  1656.     if (mclass != 1)
  1657.         gFlush(sobj);
  1658.     gTLineDirective(sobj);
  1659.  
  1660.     vPrintf(sobj, "\nstatic\t%s\t%s(object self, ...)\n{\n",
  1661.         rtn = gStringValue(gReturnType(prototype)),
  1662.         olmname);
  1663.     if (gSize(gParameters(prototype)) > 1)  {
  1664.         gPuts(sobj, "\tva_list\t_rest_;\n");
  1665.  
  1666.         while (pnxt = gNext(pseq), vnxt = gNext(vseq))
  1667.             if (i++  &&  strne(t=gStringValue(pnxt), "..."))
  1668.                 vPrintf(sobj, "\t%s\t%s;\n",
  1669.                     t, gStringValue(vnxt));
  1670.         gPuts(sobj, "\tva_start(_rest_, self);\n");
  1671.         pseq = gSequence(pvar);
  1672.         vseq = gSequence(vvar);
  1673.         i = 0;
  1674.         while (pnxt = gNext(pseq), vnxt = gNext(vseq))
  1675.             if (i++  &&  strne(t=gStringValue(pnxt), "..."))
  1676.                 vPrintf(sobj, "\t%s = va_arg(_rest_, %s);\n",
  1677.                     gStringValue(vnxt), t);
  1678.     }  else  {
  1679.         DISPOSE(pseq);
  1680.         DISPOSE(vseq);
  1681.     }
  1682.     if (streq(rtn, "void"))
  1683.         vPrintf(sobj, "\t%s(", mname);
  1684.     else
  1685.         vPrintf(sobj, "\treturn %s(", mname);
  1686.     gPrintVars(prototype, sobj);
  1687.     gPuts(sobj, ");\n}\n\n");
  1688. }
  1689.  
  1690. static    void
  1691. generate_overloaded_method(char        *olmname,
  1692.                object    olpt,
  1693.                int        mclass,
  1694.                object    sobj,
  1695.                char        *mname,
  1696.                object    prototype)
  1697. {
  1698.     int    i=0, rest_used = 0;
  1699.     char    *t, *rtn;
  1700.     object    pseq, vseq, pnxt, vnxt;
  1701.     
  1702.     if (!prototype  ||  !(pseq = gPrototype(prototype)))
  1703.         return;
  1704.     if (!(vseq = gParameters(prototype)))
  1705.         return;
  1706.     pseq = gSequence(pseq);
  1707.     vseq = gSequence(vseq);
  1708.     if (mclass != 1)
  1709.         gFlush(sobj);
  1710.     gTLineDirective(sobj);
  1711.     vPrintf(sobj, "\n%s\t%s\t%s(object self, va_list _rest_)\n",
  1712.         mclass == 1 ? "ivmeth" : "cvmeth",
  1713.         rtn = gStringValue(gReturnType(olpt)),
  1714.         olmname);
  1715.     gPuts(sobj, "{\n");
  1716.     while (pnxt = gNext(pseq), vnxt = gNext(vseq))
  1717.         if (i++  &&  strne(t=gStringValue(pnxt), "..."))  {
  1718.             vPrintf(sobj, "\t%s\t%s = va_arg(_rest_, %s);\n",
  1719.                 t, gStringValue(vnxt), t);
  1720.             rest_used = 1;
  1721.         }
  1722.     if (!rest_used)
  1723.         gPuts(sobj, "\tUSE(_rest_);\n");
  1724.     if (streq(rtn, "void"))
  1725.         vPrintf(sobj, "\t%s(", mname);
  1726.     else
  1727.         vPrintf(sobj, "\treturn %s(", mname);
  1728.     gPrintVars(prototype, sobj);
  1729.     gPuts(sobj, ");\n");
  1730.     gPuts(sobj, "}\n\n");
  1731. }
  1732.  
  1733. static    void
  1734. pp_method(object  tkn,
  1735.       object  fobj,
  1736.       object  methods,
  1737.       object  sgenerics,
  1738.       object  sobj,
  1739.       char      *mtype,
  1740.       int      mclass,  /*  1=instance,  2=class method  */
  1741.       int      vararg,   /*  1= force varargs  */
  1742.       object  ivars,
  1743.       object  cvars,
  1744.       object  className)
  1745. {
  1746.     char    type[256], mname[MAXWORDSZ+1], gname[MAXWORDSZ+1], *p=NULL, *g;
  1747.     char    olmname[MAXWORDSZ+1]; /* overloaded method name - name of dpp
  1748.                        generated method  */
  1749.     char    fmname[MAXWORDSZ+1];  /* fixed arg method name - generated  */
  1750.     char    ename[MAXWORDSZ+1];   /* explicit method name  */
  1751.     object    prototype, args;
  1752.     object    generics;    /*  linked list of generic names  */
  1753.     object    olgens;        /*  overloaded generics          */
  1754.     object    seq, obj;    /*  used for sequencing through generics  */
  1755.     int    old;
  1756.     int    oload = 0;    /*  1=overloaded generic (no arg checking)  */
  1757.     object    olpt=NULL;    /*  overloaded prototype   */
  1758.     int    famf=0;        /*  1=at least 1 fixed argument method found */
  1759.  
  1760.     *type = *gname = *ename = '\0';
  1761.     gFlush(sobj);
  1762.     if (ExtraLineDirectives)
  1763.         gForceLineDirective(sobj);
  1764.     gChangeToken(tkn, mtype);
  1765.     gPut(sobj, tkn);
  1766.     generics = gNew(LinkObject);
  1767.     olgens = gNew(LinkObject);
  1768.     while (1)  {
  1769.         if (tkn = gNextToken(fobj))
  1770.             p = gStringValue(tkn);
  1771.         if (!tkn  ||  *p == '('  ||  *p == ':'  ||  *p == ',')
  1772.             break;
  1773.  
  1774.         if (p[0] == '<'  &&  !p[1])  {
  1775.             tkn = get_olname(fobj, tkn, &p);
  1776.             if (!tkn)
  1777.                 break;
  1778.             oload = 1;
  1779.         }
  1780.         
  1781.         if (*type)
  1782.             strcat(type, " ");
  1783.         if (streq(gname, "object"))
  1784.             strcat(type, "objrtn");
  1785.         else
  1786.             strcat(type, gname);
  1787.         strcpy(gname, p);
  1788.         DISPOSE(tkn);
  1789.     }
  1790.     if (!*type)
  1791.         strcpy(type, "objrtn");
  1792.     if (!*gname  ||  !istart(*gname))  {
  1793.         method_syntax(tkn, generics, olgens);
  1794.         return;
  1795.     }
  1796.     if (oload)  {
  1797.         if (AllowOverloads  &&  !vararg)
  1798.             gAddLast(olgens, gNewWithStr(String, gname));
  1799.     }  else  {
  1800.         famf = 1;
  1801.         gAddLast(generics, gNewWithStr(String, gname));
  1802.     }
  1803.     if (tkn)
  1804.         if (*p == ',')  {
  1805.             DISPOSE(tkn);
  1806.             while (1)  {
  1807.                 if (tkn = gNextToken(fobj))
  1808.                     p = gStringValue(tkn);
  1809.                 if (!tkn  ||  *p == '('  ||  *p == ':')
  1810.                     break;
  1811.                 if (*p == ',')  {
  1812.                     DISPOSE(tkn);
  1813.                     continue;
  1814.                 }
  1815.                 if (oload = p[0] == '<'  &&  !p[1])  {
  1816.                     tkn = get_olname(fobj, tkn, &p);
  1817.                     if (!tkn)
  1818.                         break;
  1819.                 }
  1820.                 if (!istart(*p))  {
  1821.                     method_syntax(tkn, generics, olgens);
  1822.                     return;
  1823.                 }
  1824.                 if (oload)  {
  1825.                     if (AllowOverloads  &&  !vararg)
  1826.                         gAddLast(olgens, gNewWithStr(String, p));
  1827.                 }  else  {
  1828.                     famf = 1;
  1829.                     gAddLast(generics, gNewWithStr(String, p));
  1830.                 }
  1831.                 DISPOSE(tkn);
  1832.             }
  1833.         }
  1834.     if (tkn  &&  *p == ':')  {
  1835.         DISPOSE(tkn);
  1836.         if (tkn = gNextToken(fobj))
  1837.             p = gStringValue(tkn);
  1838.         if (tkn  &&  *p != '(')  {
  1839.             if (!istart(*p))  {
  1840.                 method_syntax(tkn, generics, olgens);
  1841.                 return;
  1842.             }
  1843.             strcpy(ename, p);
  1844.             sprintf(fmname, "%s_%cfm_%s", gStringValue(className),
  1845.                 mclass==1?'i':'c', gname);
  1846.             sprintf(mname, "%s_%c%sm_%s", gStringValue(className),
  1847.                 mclass==1?'i':'c', vararg?"v":"", gname);
  1848.             if (gSize(olgens))
  1849.                 sprintf(olmname, "%s_%cvm_%s", gStringValue(className),
  1850.                     mclass==1?'i':'c', mname);
  1851.             else
  1852.                 *olmname = '\0';
  1853.             DISPOSE(tkn);
  1854.             if (tkn = gNextToken(fobj))
  1855.                 p = gStringValue(tkn);
  1856.         }
  1857.     } else  {
  1858.         sprintf(mname, "%s_%c%sm_%s", gStringValue(className),
  1859.             mclass==1?'i':'c', vararg?"v":"", gname);
  1860.         sprintf(fmname, "%s_%cfm_%s", gStringValue(className),
  1861.             mclass==1?'i':'c', gname);
  1862.         if (gSize(olgens))
  1863.             sprintf(olmname, "%s_%cvm_%s", gStringValue(className),
  1864.                 mclass==1?'i':'c', gname);
  1865.         else
  1866.             *olmname = '\0';
  1867.     }
  1868.  
  1869.     if (tkn  &&  *p == '(')  {
  1870.         
  1871.         prototype = gNewWithStrStr(Prototype, mname, type);
  1872.         args = pp_make_arg_list(fobj, &old, ivars, cvars, vararg);
  1873.  
  1874.         /*   never old!
  1875.              if (old)
  1876.              gDeepDispose(args);
  1877.              else
  1878.              */
  1879.         gSetArgs(prototype, args);
  1880.         if (vararg)
  1881.             gVarArg(prototype);
  1882.  
  1883.         if (*ename)
  1884.             if (Strategy != 1  &&  gIsVarArg(prototype))
  1885.                 strcpy(fmname, ename);
  1886.             else  {
  1887.                 strcpy(mname, ename);
  1888.                 gChangeName(prototype, mname);
  1889.             }
  1890.  
  1891.         for (seq=gSequence(generics) ; obj=gNext(seq) ; )  {
  1892.             g = gStringValue(obj);
  1893.             if (!gFindStr(sgenerics, g))
  1894.                 gAddStr(sgenerics, g, gNewWithStr(String, mname));
  1895.         }
  1896.         generics = DEEPDISPOSE(generics);
  1897.  
  1898.         if (Strategy == 1  &&  *olmname)  {
  1899.             *olmname = '\1';  /*  kludge to cause the same method
  1900.                           to have two signatures  */
  1901.             strcpy(olmname+1, mname);
  1902.         }
  1903.         for (seq=gSequence(olgens) ; obj=gNext(seq) ; )  {
  1904.             g = gStringValue(obj);
  1905.             if (!gFindStr(sgenerics, g))
  1906.                 gAddStr(sgenerics, g, gNewWithStr(String, olmname));
  1907.         }
  1908.         olgens = DEEPDISPOSE(olgens);
  1909.     
  1910.         gPut(sobj, gNewToken(Token, type, 0L, 1));
  1911.         gPut(sobj, gNewToken(Token, mname, 0L, 0));
  1912.         gPut(sobj, tkn);
  1913.         gPrintMethArgs(prototype, sobj, Strategy, vararg);
  1914.  
  1915.         
  1916.         if (tkn = gNextToken(fobj))
  1917.             p = gStringValue(tkn);
  1918.         if (tkn)
  1919.             if (*p == '{')  { /*  start of method defn  */
  1920.                 if (famf)
  1921.                     if (!gFindStr(methods, mname))
  1922.                         gAddStr(methods, mname, prototype);
  1923.                     else  {
  1924.                         vPrintf(stdoutStream, "Duplicate definition for method %s\n", trunc_mname(mname));
  1925.                         ErrorCode = 1;
  1926.                         prototype = DEEPDISPOSE(prototype);
  1927.                     }
  1928.                 if (prototype  &&  !vararg  &&  *olmname)  {
  1929.                     olpt = gDeepCopy(prototype);
  1930.                     gChangeName(olpt, olmname);
  1931.                     gVarArg(olpt);
  1932.                     if (!gFindStr(methods, olmname))
  1933.                         gAddStr(methods, olmname, olpt);
  1934.                     else  {
  1935.                         vPrintf(stdoutStream, "Duplicate definition for method %s\n", trunc_mname(olmname));
  1936.                         ErrorCode = 1;
  1937.                         olpt = DEEPDISPOSE(olpt);
  1938.                     }
  1939.                 }
  1940.             } else if (*p == ','  ||  *p == ';') /*  declaration  */
  1941.                 prototype = DEEPDISPOSE(prototype);
  1942.             else  {    /*  old style func defn  */
  1943.                 vPrintf(stdoutStream, "Method %s is using old style K&R function defn.\n", trunc_mname(mname));
  1944.                 ErrorCode = 1;
  1945.                 prototype = DEEPDISPOSE(prototype);
  1946.             }
  1947.         else
  1948.             prototype = DEEPDISPOSE(prototype);
  1949.  
  1950.         /*  process method body  */
  1951.  
  1952.         pp_body(p, fobj, sobj, mclass, tkn, vararg, prototype);
  1953.         if (Strategy != 1)  {
  1954.             if (prototype  &&  gIsVarArg(prototype))  {
  1955.                 if (vararg)
  1956.                     generate_fixed_arg_vmeth(fmname, mname, prototype, mclass, sobj);
  1957.                 else
  1958.                     generate_fixed_arg_meth(fmname, mname, prototype, mclass, sobj);
  1959.                 gChangeFixedName(prototype, fmname);
  1960.             }
  1961.             if (olpt)  {
  1962.                 int    optimize = gIsVarArg(prototype)  &&  2 == gSize(gArgs(prototype));
  1963.                 if (prototype  &&  !optimize)  {
  1964.                     char    olmname2[MAXWORDSZ+1];
  1965.                     sprintf(olmname2, "_%s", olmname);
  1966.                     generate_fixed_arg_vmeth2(olmname2, mname, prototype, mclass, sobj);
  1967.                     gChangeFixedName(olpt, olmname2);
  1968.                 } else if (gIsVarArg(prototype))
  1969.                     gChangeFixedName(olpt, fmname);
  1970.                 else
  1971.                     gChangeFixedName(olpt, mname);
  1972.                 if (optimize)
  1973.                     gChangeName(olpt, mname);
  1974.                 else
  1975.                     generate_overloaded_method(olmname, olpt, mclass, sobj, mname, prototype);
  1976.                 if (!famf)
  1977.                     prototype = DEEPDISPOSE(prototype);
  1978.             }
  1979.         }
  1980.     } else {
  1981. /*        pp_body(p, fobj, sobj, 0, tkn, 0, NULL);  */
  1982.         gPut(sobj, gNewToken(Token, type, 0L, 1));
  1983.         gPut(sobj, gNewToken(Token, mname, 0L, 0));
  1984.         method_syntax(tkn, generics, olgens);
  1985.     }
  1986. }
  1987.  
  1988. static    void
  1989. pp_local_method(object  tkn,
  1990.         object  fobj,
  1991.         object  sobj,
  1992.         char    *mtype,
  1993.         int    mclass,  /*  1=instance,  2=class method  */
  1994.         object  ivars,
  1995.         object  cvars)
  1996. {
  1997.     char    type[256], mname[MAXWORDSZ+1], *p=NULL;
  1998.     object    args, prototype;
  1999.     int    old;
  2000.  
  2001.     *type = *mname = '\0';
  2002.     gFlush(sobj);
  2003.     gChangeToken(tkn, mtype);
  2004.     gPut(sobj, tkn);
  2005.     while (1)  {
  2006.         if (tkn = gNextToken(fobj))
  2007.             p = gStringValue(tkn);
  2008.         if (!tkn  ||  *p == '(')
  2009.             break;
  2010.         if (*type)
  2011.             strcat(type, " ");
  2012.         if (streq(mname, "object"))
  2013.             strcat(type, "objrtn");
  2014.         else
  2015.             strcat(type, mname);
  2016.         strcpy(mname, p);
  2017.         DISPOSE(tkn);
  2018.     }
  2019.     if (!*type)
  2020.         strcpy(type, "objrtn");
  2021.     if (!*mname  ||  !istart(*mname))  {
  2022.         method_syntax(tkn, NULL, NULL);
  2023.         return;
  2024.     }
  2025.  
  2026.     gPut(sobj, gNewToken(Token, type, 0L, 1));
  2027.     gPut(sobj, gNewToken(Token, mname, 0L, 0));
  2028.  
  2029.     if (tkn  &&  *p == '(')  {
  2030.         gPut(sobj, tkn);
  2031.         
  2032.         prototype = gNewWithStrStr(Prototype, mname, type);
  2033.         args = pp_make_arg_list(fobj, &old, ivars, cvars, 0);
  2034.  
  2035.         gSetArgs(prototype, args);
  2036.         gPrintMethArgs(prototype, sobj, Strategy, 0);
  2037.  
  2038.         if (tkn = gNextToken(fobj))
  2039.             p = gStringValue(tkn);
  2040.  
  2041.         DEEPDISPOSE(prototype);
  2042.  
  2043.         /*  process method body  */
  2044.  
  2045.         pp_body(p, fobj, sobj, mclass, tkn, 0, NULL);
  2046.  
  2047.     } else
  2048. /*        pp_body(p, fobj, sobj, 0, tkn, 0, NULL);  */
  2049.         method_syntax(tkn, NULL, NULL);
  2050. }
  2051.  
  2052. #define    PUT(s, x)                \
  2053.         tkn = gNewToken(Token, x, 0L, s);    \
  2054.     if (mclass == 1)            \
  2055.         gPutm(sobj, tkn);        \
  2056.     else                    \
  2057.         gPut(sobj, tkn)
  2058.  
  2059. #define    PUT_SEMI                \
  2060.         tkn = gNewToken(Token, ";", 0L, 0);    \
  2061.     if (mclass == 1)            \
  2062.         gPutm(sobj, tkn);        \
  2063.     else                    \
  2064.         gPut(sobj, tkn)
  2065.  
  2066. static    void    expand_get_args(object    prototype,
  2067.                 int    mclass,
  2068.                 object    sobj)
  2069. {
  2070.     object    tkn, pseq, vseq, pnxt, vnxt;
  2071.     int    i = 0;
  2072.     char    *t;
  2073.  
  2074.     if (!(pseq = gPrototype(prototype)))
  2075.         return;
  2076.     if (!(vseq = gParameters(prototype)))
  2077.         return;
  2078.     pseq = gSequence(pseq);
  2079.     vseq = gSequence(vseq);
  2080.     if (mclass != 1)
  2081.         gFlush(sobj);
  2082.     while (pnxt = gNext(pseq), vnxt = gNext(vseq))
  2083.         if (i++  &&  strne(t=gStringValue(pnxt), "..."))  {
  2084.             PUT(1, t);
  2085.             PUT(1, gStringValue(vnxt));
  2086.             PUT(1, "=");
  2087.             PUT(0, "va_arg");
  2088.             PUT(0, "(");
  2089.             PUT(0, "_rest_");
  2090.             PUT(1, ",");
  2091.             PUT(0, t);
  2092.             PUT(0, ")");
  2093.             PUT_SEMI;
  2094.         }
  2095. /*
  2096.     PUT(0, "va_end");
  2097.     PUT(0, "(");
  2098.     PUT(0, "_rest_");
  2099.     PUT(0, ")");
  2100.     PUT_SEMI;
  2101. */
  2102. }
  2103.  
  2104.  
  2105. /*  process between braces  */
  2106.  
  2107. static    void
  2108. pp_body(char    *p,
  2109.     object  fobj,
  2110.     object  sobj,
  2111.     int     mclass,   /*  1=instance,  2=class method  0=neither */
  2112.     object    tkn,
  2113.     int    convert,  /*  1=decode GET_ARGS        */
  2114.     object    prototype)
  2115. {
  2116.     int    bracelevel = 1;
  2117.  
  2118.     if (!tkn)
  2119.         return;
  2120.     if (*p != '{')  {
  2121.         gPut(sobj, tkn);
  2122.         return;
  2123.     }
  2124.  
  2125.     if (mclass == 1)  {        /*  instance  */
  2126.         gFlush(sobj);
  2127.         gPutm(sobj, tkn);
  2128.     }  else
  2129.         gPut(sobj, tkn);
  2130.  
  2131.     if (convert  &&  Strategy != 1  &&  prototype)
  2132.         expand_get_args(prototype, mclass, sobj);
  2133.             
  2134.     while (bracelevel  &&  tkn  &&  (tkn = gNextToken(fobj)))  {
  2135.         p = gStringValue(tkn);
  2136.         if (*p == '}'  &&  bracelevel)
  2137.             bracelevel--;
  2138.         else if (*p == '{')
  2139.             bracelevel++;
  2140. #if 0
  2141.         if (streq(p, "GET_ARGS"))  {
  2142.             if (convert  &&  Strategy != 1  &&  prototype)
  2143.                 expand_get_args(prototype, mclass, sobj, gLineNumber(tkn));
  2144.             tkn = gNextToken(fobj);  /*  get rid of trailing ; */
  2145.         } else
  2146. #endif
  2147.         if (mclass == 1)
  2148.             gPutm(sobj, tkn);
  2149.         else
  2150.             gPut(sobj, tkn);
  2151.     }
  2152.     if (mclass == 1)
  2153.         gFlushm(sobj);
  2154. /*                causes problems with macros with several sets
  2155.                 of braces
  2156.     else
  2157.         gFlush(sobj);
  2158. */
  2159. }
  2160.  
  2161. static    void    src_generic(object fobj, object sgenerics)
  2162. {
  2163.     char    gname[MAXWORDSZ+2], *tkn;
  2164.  
  2165.     tkn = gettoken(fobj);
  2166.     if (!tkn  ||  *tkn != '(')
  2167.         return;
  2168.     
  2169.     tkn = gettoken(fobj);
  2170.     if (!tkn)
  2171.         return;
  2172.  
  2173.     sprintf(gname, "g%s", tkn);
  2174.     
  2175.     if (!gFindStr(sgenerics, gname))
  2176.         gAddStr(sgenerics, gname, gNewWithStr(String, tkn));
  2177. /*  it's ok because sometimes there is a class and instance method which use
  2178.     the same generic
  2179.     else
  2180.         vPrintf(stdoutStream, "Generic %s is associated with more than one method within a single source file\n", gname);
  2181. */
  2182. }
  2183.  
  2184. static    void    src_generic2(object fobj, object sgenerics)
  2185. {
  2186.     char    cname[MAXWORDSZ+2], gname[MAXWORDSZ+2], *tkn;
  2187.  
  2188.     tkn = gettoken(fobj);
  2189.     if (!tkn  ||  *tkn != '(')
  2190.         return;
  2191.     
  2192.     tkn = gettoken(fobj);
  2193.     if (!tkn  ||  !istart(*tkn))
  2194.         return;
  2195.     strcpy(cname, tkn);
  2196.  
  2197.     tkn = gettoken(fobj);
  2198.     if (!tkn  ||  *tkn != ',')
  2199.         return;
  2200.     
  2201.     tkn = gettoken(fobj);
  2202.     if (!tkn  ||  !istart(*tkn))
  2203.         return;
  2204.     strcpy(gname, tkn);
  2205.  
  2206.     tkn = gettoken(fobj);
  2207.     if (!tkn  ||  *tkn != ',')
  2208.         return;
  2209.  
  2210.     tkn = gettoken(fobj);
  2211.     if (!tkn  ||  !istart(*tkn))
  2212.         return;
  2213.     
  2214.     if (!gFindStr(sgenerics, gname))
  2215.         gAddStr(sgenerics, gname, gNewWithStr(String, tkn));
  2216. /*  it's ok because sometimes there is a class and instance method which use
  2217.     the same generic
  2218.     else
  2219.         vPrintf(stdoutStream, "Generic %s is associated with more than one method within a single source file\n", gname);
  2220. */
  2221. }
  2222.  
  2223. static    void
  2224. addto_generics(object smethods,        /*  source methods          */
  2225.            object sgenerics,    /*  source generics        */
  2226.            object generics,        /*  global generics        */
  2227.            object exceptions)    /*  generic exceptions        */
  2228. {
  2229.     object    seq, obj, mproto, gproto, mnobj, gnobj;
  2230.     char    *gname, *mname;
  2231.     object    usedMethods;    /*  set of used methods  */
  2232.  
  2233.     usedMethods = gNewWithInt(Set, 41);
  2234.     for (seq = gSequence(sgenerics) ; obj = gNext(seq) ; )  {
  2235.         gname = gStringKey(obj);
  2236.         mname = gStringValue(mnobj=gValue(obj));
  2237.         mproto = gFindValueStr(smethods, mname);
  2238.         if (!mproto)  {
  2239.             ErrorCode = 1;
  2240.             vPrintf(stdoutStream, "Missing method definition %s in source file.\n", mname);
  2241.             continue;
  2242.         }
  2243.         gAdd(usedMethods, mnobj);
  2244.         gproto = gFindValueStr(generics, gname);
  2245.         if (!gproto)  {
  2246.             gproto = gDeepCopy(mproto);
  2247.             gChangeName(gproto, gname);
  2248.             gnobj = gNewWithStr(String, gname);
  2249.             if (NoProto  ||  gFind(exceptions, gnobj))
  2250.                 gException(gproto);
  2251.             DISPOSE(gnobj);
  2252.             add_generic(generics, gname, gproto, 1);
  2253.         }  else
  2254.             ErrorCode |= gMatch(gproto, mproto);
  2255.     }
  2256.     for (seq = gSequence(smethods) ; obj = gNext(seq) ; )
  2257.         if (!InKernel  &&  !gFind(usedMethods, gGetMGName(gValue(obj))))  {
  2258.             ErrorCode = 1;
  2259.             vPrintf(stdoutStream, "Method %s has not been assigned to any generic.\n",
  2260.                 gStringKey(obj));
  2261.         }
  2262.     DISPOSE(usedMethods);
  2263. }
  2264.  
  2265. static    void
  2266. public_meth(char    *p,
  2267.         object    tkn,
  2268.         object    fobj,
  2269.         object    sobj,
  2270.         object    ismethods,
  2271.         object    csmethods,
  2272.         object    isgenerics, 
  2273.         object    csgenerics,
  2274.         object    ivars,
  2275.         object    cvars,
  2276.         object    className)
  2277. {
  2278.     if (streq(p, "imeth"))
  2279.         pp_method(tkn, fobj, ismethods, isgenerics, sobj,
  2280.               "imeth", 1, 0, ivars, cvars, className);
  2281.     else if (streq(p, "cmeth"))
  2282.         pp_method(tkn, fobj, csmethods, csgenerics, sobj,
  2283.               "cmeth", 2, 0, ivars, cvars, className);
  2284.     else if (streq(p, "ivmeth"))
  2285.         pp_method(tkn, fobj, ismethods, isgenerics, sobj,
  2286.               "ivmeth", 1, 1, ivars, cvars, className);
  2287.     else if (streq(p, "cvmeth"))
  2288.         pp_method(tkn, fobj, csmethods, csgenerics, sobj,
  2289.               "cvmeth", 2, 1, ivars, cvars, className);
  2290. }
  2291.  
  2292. static    void
  2293. private_meth(char    *p,
  2294.          object    tkn,
  2295.          object    fobj,
  2296.          object    sobj,
  2297.          object    ivars,
  2298.          object    cvars)
  2299. {
  2300.     if (streq(p, "imeth")  ||  streq(p, "ivmeth"))
  2301.         pp_local_method(tkn, fobj, sobj, "static", 1, ivars, cvars);
  2302.     else if (streq(p, "cmeth")  ||  streq(p, "cvmeth"))
  2303.         pp_local_method(tkn, fobj, sobj, "static", 2, ivars, cvars);
  2304. }
  2305.  
  2306. #define AMETH(p)    streq(p, "imeth")   ||        \
  2307.                     streq(p, "cmeth")   ||        \
  2308.             streq(p, "ivmeth")  ||        \
  2309.             streq(p, "cvmeth")
  2310.  
  2311. static    void
  2312. preprocess(object    classes,
  2313.        object     generics,
  2314.        char        *file,
  2315.        object    exceptions,
  2316.        int        mkc)    /*  1=create .c file, 0=just parse  */
  2317. {
  2318.     object    fobj;        /*  source file (.d)            */
  2319.     object    sobj;        /*  target source file (.c)        */
  2320.     char    sfile[50];    /*  .c file name              */
  2321.     object    tkn;        /*  token                */
  2322.     object    className;    /*  String                */
  2323.     object    superClasses;    /*  LinkObject                */
  2324.     object    idecls;        /*  instance declarations - LinkObject  */
  2325.     object    cdecls;        /*  class declarations - LinkObject    */
  2326.     object    ivars;        /*  instance variables - Set        */
  2327.     object    cvars;        /*  class variables - Set        */
  2328.     object    init;        /*  init function - String        */
  2329.     object    ismethods;    /*  instance method + method prototype     */
  2330.     object    isgenerics;    /*  instance generic + method        */
  2331.     object    csmethods;    /*  class method + method prototype      */
  2332.     object    csgenerics;    /*  class generic + method        */
  2333.     char    *p;        /*  pointer to token string        */
  2334.     int    defclass = 0;    /*  number of defclass's        */
  2335.     char    *ext;        /*  file extension            */
  2336.     int    pub = 0;    /*  public keyword seen            */
  2337.     int    priv = 0;    /*  private keyword seen        */
  2338.     int    sciv = Create_iv;  /*  save it                */
  2339.     int    sccv = Create_cv;  /*  save it                */
  2340.     
  2341.     if (!class_source(file))  {
  2342.         ErrorCode = 1;
  2343.         vPrintf(stdoutStream, "File %s should end with .d or .dd\n", file);
  2344.         return;
  2345.     }
  2346.     ext = file_extension(file);
  2347.     strcpy(sfile, file);
  2348. #ifdef    unix
  2349.     strcpy(sfile+(ext-file), ext[0] == ext[1] ? "cc" : "c");
  2350. #else
  2351.     strcpy(sfile+(ext-file), ext[0] == ext[1] ? "cpp" : "c");
  2352. #endif
  2353.  
  2354.     if (NULL == (fobj = gNewWithStr(InputStream, file)))
  2355.         return;
  2356.     if (NULL == (sobj = gNewWithStrStr(OutputStream, mkc ? sfile : (char *) NULL, file)))  {
  2357.         gDispose(fobj);
  2358.         return;
  2359.     }
  2360.     if (Copyright)
  2361.         copyright(sobj);
  2362. #ifndef    DBI
  2363.     gPuts(sobj,"\n\n/*  This file automatically generated by dpp - do not edit  */\n\n");
  2364.     vPrintf(sobj, "#define\tDPP_STRATEGY\t%d\n", Strategy);
  2365.     vPrintf(sobj, "#define\tDPP_FASTWIDE\t%d\n\n\n", FastWideCache);
  2366. #endif
  2367.  
  2368.     className = gNew(String);
  2369.     superClasses = gNew(LinkObject);
  2370.     idecls = gNew(LinkObject);
  2371.     cdecls = gNew(LinkObject);
  2372.     ivars = gNewWithInt(Set, 21);
  2373.     cvars = gNewWithInt(Set, 21);
  2374.     init = gNew(String);
  2375.  
  2376.     isgenerics = gNewWithInt(StringDictionary, 301);
  2377.     ismethods  = gNewWithInt(StringDictionary, 301);
  2378.     csgenerics = gNewWithInt(StringDictionary, 301);
  2379.     csmethods  = gNewWithInt(StringDictionary, 301);
  2380.     while (tkn=gNextToken(fobj))  {
  2381.         p = gStringValue(tkn);
  2382.         if (streq(p, "public"))  {
  2383.             pub = 1;
  2384.             priv = 0;
  2385.             DISPOSE(tkn);
  2386.         } else if (streq(p, "private"))  {
  2387.             pub = 0;
  2388.             priv = 1;
  2389.             DISPOSE(tkn);
  2390.         } else if (streq(p, "defclass"))  {
  2391.             if (defclass++)  {
  2392.                 vPrintf(stdoutStream, "File has multiple defclass's\n");
  2393.                 ErrorCode = 1;
  2394.             }
  2395.             if (pub  &&  mkc)
  2396.                 Create_iv = Create_cv = 1;
  2397.             pp_defclass(tkn, fobj, className, superClasses, idecls,
  2398.                     cdecls, ivars, cvars, init, classes);
  2399. #ifndef DBI
  2400.             pp_gen_head(sobj, className, idecls, cdecls,
  2401.                     ivars, cvars, file);
  2402. #else
  2403.             gPuts(sobj, "\n//--------------------   t.c   --------------------");
  2404. #endif
  2405.             gSetOSVars(sobj, className, cvars, ivars);
  2406.             pub = priv = 0;
  2407.         } else if (AMETH(p))  {
  2408.             if (!priv)
  2409.                 public_meth(p, tkn, fobj, sobj, ismethods, csmethods,
  2410.                         isgenerics, csgenerics, ivars, cvars, className);
  2411.             else
  2412.                 private_meth(p, tkn, fobj, sobj, ivars, cvars);
  2413.             pub = priv = 0;
  2414.         }  else  {
  2415.             if (pub)
  2416.                 gPut(sobj, gNewToken(Token, "public", 0L, 0));
  2417.             if (priv)
  2418.                 gPut(sobj, gNewToken(Token, "private", 0L, 0));
  2419.             pp_body(p, fobj, sobj, 0, tkn, 0, NULL);
  2420.             pub = priv = 0;
  2421.         }
  2422.     }
  2423.     if (defclass  &&  !NoInitialize)
  2424.         pp_gen_initmethod(sobj, superClasses, init, isgenerics,
  2425.                   csgenerics, ismethods, csmethods,
  2426.                   ivars, cvars, className);
  2427.     gDispose(fobj);
  2428.     gDispose(sobj);
  2429.     if (defclass)  {
  2430.         if (Create_iv)
  2431.             pp_gen_iv(file, className, idecls);
  2432.         if (Create_cv)
  2433.             pp_gen_cv(file, className, cdecls);
  2434.     }
  2435.     addto_generics(ismethods, isgenerics, generics, exceptions);
  2436.     addto_generics(csmethods, csgenerics, generics, exceptions);
  2437. #if 0
  2438.     gPuts(stdoutStream, "className = ");
  2439.     gPrint(className, stdoutStream);
  2440.  
  2441.     gPuts(stdoutStream, "\nsuperClasses = ");
  2442.     gPrint(superClasses, stdoutStream);
  2443.  
  2444.     gPuts(stdoutStream, "\nidecls = ");
  2445.     gPrint(idecls, stdoutStream);
  2446.  
  2447.     gPuts(stdoutStream, "\ncdecls = ");
  2448.     gPrint(cdecls, stdoutStream);
  2449.     
  2450.     gPuts(stdoutStream, "\nivars = ");
  2451.     gPrint(ivars, stdoutStream);
  2452.     
  2453.     gPuts(stdoutStream, "\ncvars = ");
  2454.     gPrint(cvars, stdoutStream);
  2455.     
  2456.     gPuts(stdoutStream, "\ninit = ");
  2457.     gPrint(init, stdoutStream);
  2458.     
  2459.     gPuts(stdoutStream, "\nisgenerics = ");
  2460.     gPrint(isgenerics, stdoutStream);
  2461.     
  2462.     gPuts(stdoutStream, "\nismethods = ");
  2463.     gPrint(ismethods, stdoutStream);
  2464.     
  2465.     gPuts(stdoutStream, "\ncsgenerics = ");
  2466.     gPrint(csgenerics, stdoutStream);
  2467.     
  2468.     gPuts(stdoutStream, "\ncsmethods = ");
  2469.     gPrint(csmethods, stdoutStream);
  2470.     
  2471. #endif
  2472.     DEEPDISPOSE(className);
  2473.     DEEPDISPOSE(superClasses);
  2474.     DEEPDISPOSE(idecls);
  2475.     DEEPDISPOSE(cdecls);
  2476.     DEEPDISPOSE(ivars);
  2477.     DEEPDISPOSE(cvars);
  2478.     DEEPDISPOSE(init);
  2479.     DEEPDISPOSE(ismethods);
  2480.     DEEPDISPOSE(isgenerics);
  2481.     DEEPDISPOSE(csmethods);
  2482.     DEEPDISPOSE(csgenerics);
  2483.  
  2484.     Create_iv = sciv;
  2485.     Create_cv = sccv;
  2486. }
  2487.  
  2488. static    void
  2489. pp_gen_head(object    sobj,
  2490.         object    className,
  2491.         object    idecls,
  2492.         object    cdecls,
  2493.         object    ivars,
  2494.         object    cvars,
  2495.         char    *file)
  2496. {
  2497.     object    seq, lnk;
  2498. /*    char    *p;    */
  2499.     char    *cname;
  2500.  
  2501.     gFlush(sobj);
  2502.     gPuts(sobj, "\n");
  2503.     vPrintf(sobj, "#define\tCLASS\t%s_c\n", cname=gStringValue(className));
  2504.     vPrintf(sobj, "#define\tivType\t%s_iv_t\n", cname);
  2505.     gPuts(sobj, "\n");
  2506.     if (GenIncludes)
  2507.         gPuts(sobj, "#include \"generics.h\"\n\n");
  2508.     vPrintf(sobj, "object\t%s_c;\n\n", cname);
  2509.     if (gSize(idecls))
  2510.         if (Create_iv)
  2511.             vPrintf(sobj, "#include \"%s\"\n\n", new_ext(file, "iv"));
  2512.         else  {
  2513.             gTLineDirective(sobj);
  2514.             vPrintf(sobj, "typedef struct  _%s_iv_t  {\n", cname);
  2515.             for (seq=gSequence(idecls) ; lnk = gNext(seq) ; )
  2516.                 vPrintf(sobj, "\t%s\n", gStringValue(lnk));
  2517.             vPrintf(sobj, "}\t%s_iv_t;\n\n", cname);
  2518.         }
  2519.     if (gSize(cdecls))  {
  2520.         if (Create_cv)
  2521.             vPrintf(sobj, "#include \"%s\"\n\n", new_ext(file, "cv"));
  2522.         else  {
  2523.             gTLineDirective(sobj);
  2524.             vPrintf(sobj, "typedef struct  _%s_cv_t  {\n", cname);
  2525.             for (seq=gSequence(cdecls) ; lnk = gNext(seq) ; )
  2526.                 vPrintf(sobj, "\t%s\n", gStringValue(lnk));
  2527.             vPrintf(sobj, "}\t%s_cv_t;\n\n", cname);
  2528.         }
  2529.         vPrintf(sobj, "static\t%s_cv_t\t*%s_cv;\n\n", cname, cname);
  2530.     }
  2531.     USE(ivars);
  2532.     USE(cvars);
  2533. }
  2534.  
  2535. static    void
  2536. pp_gen_iv(char        *file,
  2537.       object    className,
  2538.       object    idecls)
  2539. {
  2540.     object    seq, lnk, sobj;
  2541.     char    *fname, macro[60];
  2542.     char    *cname;
  2543.  
  2544.     if (!gSize(idecls))
  2545.         return;
  2546.     fname = new_ext(file, "iv");
  2547.     sobj = open_file(fname, WMODE);
  2548.     if (!sobj)
  2549.         return;
  2550.  
  2551.     make_macro_name(macro, fname);
  2552.  
  2553.     cname = gStringValue(className);
  2554.  
  2555.     vPrintf(sobj, "\n#ifndef\t%s\n", macro);
  2556.     vPrintf(sobj, "#define\t%s\n\n\n", macro);
  2557.  
  2558.     vPrintf(sobj, "typedef struct  _%s_iv_t  {\n", cname);
  2559.     for (seq=gSequence(idecls) ; lnk = gNext(seq) ; )
  2560.         vPrintf(sobj, "\t%s\n", gStringValue(lnk));
  2561.     vPrintf(sobj, "}\t%s_iv_t;\n\n", cname);
  2562.  
  2563.     vPrintf(sobj, "#endif\t/*  %s  */\n\n\n", macro);
  2564.  
  2565.     gDispose(sobj);
  2566. }
  2567.  
  2568. static    void
  2569. pp_gen_cv(char        *file,
  2570.       object    className,
  2571.       object    cdecls)
  2572. {
  2573.     object    seq, lnk, sobj;
  2574.     char    *fname, macro[60];
  2575.     char    *cname;
  2576.  
  2577.     if (!gSize(cdecls))
  2578.         return;
  2579.     fname = new_ext(file, "cv");
  2580.     sobj = open_file(fname, WMODE);
  2581.     if (!sobj)
  2582.         return;
  2583.  
  2584.     make_macro_name(macro, fname);
  2585.  
  2586.     cname = gStringValue(className);
  2587.     
  2588.     vPrintf(sobj, "\n#ifndef\t%s\n", macro);
  2589.     vPrintf(sobj, "#define\t%s\n\n\n", macro);
  2590.  
  2591.     vPrintf(sobj, "typedef struct  _%s_cv_t  {\n", cname);
  2592.     for (seq=gSequence(cdecls) ; lnk = gNext(seq) ; )
  2593.         vPrintf(sobj, "\t%s\n", gStringValue(lnk));
  2594.     vPrintf(sobj, "}\t%s_cv_t;\n\n", cname);
  2595.  
  2596.     vPrintf(sobj, "#endif\t/*  %s  */\n\n\n", macro);
  2597.  
  2598.     gDispose(sobj);
  2599. }
  2600.  
  2601. static    void    pp_gen_links(char   type,
  2602.                  object generics,
  2603.                  object methods,
  2604.                  object sobj,
  2605.                  char   *cname)
  2606. {
  2607.     object    seq, lnk, mproto, fixedo;
  2608.     char    *gen, *meth, *fname;
  2609.  
  2610.     for (seq=gSequence(generics) ; lnk=gNext(seq) ; )  {
  2611.         /*  lnk is a StringAssociation  */
  2612.         gen = gStringKey(lnk);
  2613.         meth = gStringValue(gValue(lnk));
  2614.         mproto = gFindValueStr(methods, meth);
  2615.         if (mproto) {  /*  can be NULL if code has a methos declaration but no definition  */
  2616.             /*  in certain curcumstance this name is different!  */
  2617.             meth = gStringValue(gGetMGName(mproto));
  2618.             if (*meth == '\1')
  2619.                 meth++;  /*  the other half of a kludge to allow one
  2620.                          method name to have two signatures.  */
  2621.             if (gIsVarArg(mproto))  {
  2622.                 fixedo = gGetFixedName(mproto);
  2623.                 fname = fixedo ? gStringValue(fixedo) : meth;
  2624.                 vPrintf(sobj, "\t%cvMethodFor(%s, %s, %s, %s);\n", type, cname, gen, meth, fname);
  2625.             } else
  2626.                 vPrintf(sobj, "\t%cMethodFor(%s, %s, %s);\n", type, cname, gen, meth);
  2627.         }
  2628.     }
  2629. }
  2630.  
  2631. static    void
  2632. pp_gen_initmethod(object  sobj,
  2633.           object  superClasses,
  2634.           object  init,
  2635.           object  isgenerics,
  2636.           object  csgenerics,
  2637.           object  ismethods,
  2638.           object  csmethods, 
  2639.           object  ivars,
  2640.           object  cvars,
  2641.           object  className)
  2642. {
  2643.     object    seq, lnk;
  2644.     char    *cname = gStringValue(className);
  2645.  
  2646.     gFlush(sobj);
  2647. #ifndef    DBI
  2648.     gTLineDirective(sobj);
  2649.     vPrintf(sobj, "\nobjrtn\t%s_initialize(void)\n", cname);
  2650.     gPuts(sobj, "{\n");
  2651.     gPuts(sobj, "\tstatic  CRITICALSECTION  cs;\n");
  2652.     gPuts(sobj, "\tstatic  int volatile once = 0;\n\n");
  2653.  
  2654.     gPuts(sobj, "\tENTERCRITICALSECTION(_CI_CS_);\n");
  2655.     gPuts(sobj, "\tif (!once) {\n");
  2656.     gPuts(sobj, "\t\tINITIALIZECRITICALSECTION(cs);\n");
  2657.     gPuts(sobj, "\t\tonce = 1;\n");
  2658.     gPuts(sobj, "\t}\n");
  2659.     gPuts(sobj, "\tLEAVECRITICALSECTION(_CI_CS_);\n\n");
  2660.  
  2661.     gPuts(sobj, "\tENTERCRITICALSECTION(cs);\n\n");
  2662.  
  2663.     vPrintf(sobj, "\tif (%s_c) {\n", cname);
  2664.     gPuts(sobj, "\t\tLEAVECRITICALSECTION(cs);\n");
  2665.     vPrintf(sobj, "\t\treturn %s_c;\n", cname);
  2666.     gPuts(sobj, "\t}\n");
  2667.     gPuts(sobj, "\tINHIBIT_THREADER;\n");
  2668.  
  2669.     if (gSize(superClasses))
  2670.         for (seq=gSequence(superClasses) ; lnk = gNext(seq) ; )  {
  2671.             vPrintf(sobj, "\t%s_initialize();\n", gStringValue(lnk));
  2672.             vPrintf(sobj, "\tif (%s_c)  {\n", cname);
  2673.             gPuts(sobj, "\t\tENABLE_THREADER;\n");
  2674.             gPuts(sobj, "\t\tLEAVECRITICALSECTION(cs);\n");
  2675.             vPrintf(sobj, "\t\treturn %s_c;\n", cname);
  2676.             gPuts(sobj, "\t}\n");
  2677.         }
  2678.  
  2679.     vPrintf(sobj, "\t%s_c = gNewClass(Class, \"%s\", ", cname, cname);
  2680.     if (gSize(ivars))
  2681.         vPrintf(sobj, "sizeof(%s_iv_t), ", cname);
  2682.     else
  2683.         gPuts(sobj, "0, ");
  2684.     if (gSize(cvars))
  2685.         vPrintf(sobj, "sizeof(%s_cv_t), ", cname);
  2686.     else
  2687.         gPuts(sobj, "0, ");
  2688.     if (gSize(superClasses))
  2689.         for (seq=gSequence(superClasses) ; lnk = gNext(seq) ; )
  2690.             vPrintf(sobj, "%s, ", gStringValue(lnk));
  2691.     gPuts(sobj, "END);\n");
  2692. #endif
  2693.     
  2694.     pp_gen_links('c', csgenerics, csmethods, sobj, cname);
  2695.  
  2696.     pp_gen_links('i', isgenerics, ismethods, sobj, cname);
  2697.  
  2698. #ifndef    DBI
  2699.     gPuts(sobj, "\n");
  2700.  
  2701.     if (gSize(cvars))
  2702.         vPrintf(sobj, "\t%s_cv = GetCVs(%s);\n\n", cname, cname);
  2703.  
  2704.     if (gSize(init))
  2705.         vPrintf(sobj, "\t%s();\n\n", gStringValue(init));
  2706.  
  2707.     gPuts(sobj, "\tENABLE_THREADER;\n\n");
  2708.     gPuts(sobj, "\tLEAVECRITICALSECTION(cs);\n\n");
  2709.     vPrintf(sobj, "\treturn %s_c;\n", cname);
  2710.     gPuts(sobj, "}\n\n\n");
  2711. #else
  2712.     USE(lnk);
  2713.     USE(seq);
  2714. #endif
  2715. }
  2716.  
  2717. static    int    valid_symbol(char *tkn)
  2718. {
  2719.     if (!tkn  ||  !istart(*tkn))
  2720.         return 0;
  2721.     for (++tkn ; *tkn ; ++tkn)
  2722.         if (!irest(*tkn))
  2723.             return 0;
  2724.     return 1;
  2725. }
  2726.  
  2727. #define INSTANCE_SECTION    1
  2728. #define CLASS_SECTION        2
  2729. #define INIT_SECTION        3
  2730.  
  2731. static    void
  2732. pp_defclass(object    tkn,
  2733.         object    fobj,
  2734.         object    className,
  2735.         object    superClasses,
  2736.         object    idecls,
  2737.         object    cdecls,
  2738.         object    ivars,
  2739.         object    cvars,
  2740.         object    init,
  2741.         object    classes)
  2742. {
  2743.     char    *p=NULL;
  2744.  
  2745.     DISPOSE(tkn);
  2746.     if (tkn = gNextToken(fobj))
  2747.         p = gStringValue(tkn);
  2748.     if (!tkn  ||  !valid_symbol(p))  {
  2749.         ErrorCode = 1;
  2750.         gPuts(stdoutStream, "Class name must follow defclass.\n");
  2751.         DISPOSE(tkn);
  2752.         return;
  2753.     }
  2754.     gChangeStrValue(className, p);
  2755.     gAdd(classes, gCopy(className));
  2756.     DISPOSE(tkn);
  2757.  
  2758.     while (1)  {
  2759.         tkn = gNextToken(fobj);
  2760.         if (!tkn)
  2761.             break;
  2762.         p = gStringValue(tkn);
  2763.         if (*p == '{'  ||  *p == ';')
  2764.             break;
  2765.         if (*p == ':'  ||  *p == ',')  {
  2766.             DISPOSE(tkn);
  2767.             continue;
  2768.         }
  2769.         if (!valid_symbol(p))  {
  2770.             ErrorCode = 1;
  2771.             vPrintf(stdoutStream, "Superclass name must follow class name.\n");
  2772.             DISPOSE(tkn);
  2773.             return;
  2774.         }
  2775.         gAddLast(superClasses, gNewWithStr(String, p));
  2776.         DISPOSE(tkn);
  2777.     }
  2778.  
  2779.     if (tkn  &&  *p == '{')  {
  2780.         int    mode = INSTANCE_SECTION;
  2781.         DISPOSE(tkn);
  2782.         while (1)  {
  2783.             tkn = gNextToken(fobj);
  2784.             if (!tkn)
  2785.                 break;
  2786.             p = gStringValue(tkn);
  2787.             if (*p == '}')
  2788.                 break;
  2789.             if (streq(p, "instance"))  {
  2790.                 DISPOSE(tkn);
  2791.                 tkn = gNextToken(fobj);
  2792.                 if (!tkn)
  2793.                     break;
  2794.                 p = gStringValue(tkn);
  2795.                 if (*p != ':')  {
  2796.                     ErrorCode = 1;
  2797.                     vPrintf(stdoutStream, "Missing : after instance in defclass.\n");
  2798.                     DISPOSE(tkn);
  2799.                     return;
  2800.                 }
  2801.                 DISPOSE(tkn);
  2802.                 mode = INSTANCE_SECTION;
  2803.                 continue;
  2804.             }
  2805.             if (streq(p, "class"))  {
  2806.                 DISPOSE(tkn);
  2807.                 tkn = gNextToken(fobj);
  2808.                 if (!tkn)
  2809.                     break;
  2810.                 p = gStringValue(tkn);
  2811.                 if (*p != ':')  {
  2812.                     ErrorCode = 1;
  2813.                     vPrintf(stdoutStream, "Missing : after class in defclass.\n");
  2814.                     DISPOSE(tkn);
  2815.                     return;
  2816.                 }
  2817.                 DISPOSE(tkn);
  2818.                 mode = CLASS_SECTION;
  2819.                 continue;
  2820.             }
  2821.             if (streq(p, "init"))  {
  2822.                 DISPOSE(tkn);
  2823.                 tkn = gNextToken(fobj);
  2824.                 if (!tkn)
  2825.                     break;
  2826.                 p = gStringValue(tkn);
  2827.                 if (*p != ':')  {
  2828.                     ErrorCode = 1;
  2829.                     vPrintf(stdoutStream, "Missing : after init in defclass.\n");
  2830.                     DISPOSE(tkn);
  2831.                     return;
  2832.                 }
  2833.                 DISPOSE(tkn);
  2834.                 mode = INIT_SECTION;
  2835.                 continue;
  2836.             }
  2837.             switch (mode)  {
  2838.             case INSTANCE_SECTION:
  2839.                 pp_decl_section(tkn, p, fobj, idecls, ivars, cvars);
  2840.                 break;
  2841.             case CLASS_SECTION:
  2842.                 pp_decl_section(tkn, p, fobj, cdecls, cvars, ivars);
  2843.                 break;
  2844.             case INIT_SECTION:
  2845.                 pp_init_section(tkn, p, fobj, init);
  2846.                 break;
  2847.             }
  2848.         }
  2849.         if (tkn)  {
  2850.             DISPOSE(tkn);
  2851.             if (tkn = gNextToken(fobj))   /*  should be last ;  */
  2852.                 p = gStringValue(tkn);
  2853.         }
  2854.     }
  2855.     if (!tkn)  {
  2856.         ErrorCode = 1;
  2857.         gPuts(stdoutStream, "Incomplete defclass section.\n");
  2858.     } else     if (*p != ';')  {
  2859.         ErrorCode = 1;
  2860.         gPuts(stdoutStream, "Missing ; at end of defclass.\n");
  2861.         DISPOSE(tkn);
  2862.     } else
  2863.         DISPOSE(tkn);
  2864. }
  2865.  
  2866. static    void
  2867. pp_decl_section(object    tkn,
  2868.         char    *p,
  2869.         object    fobj,
  2870.         object    idecls,
  2871.         object    ivars,       /*  instance or class variable to add to  */
  2872.         object    ovars)      /*  other var list which should not have dup */
  2873. {
  2874.     char    buf[256], var[100];
  2875.     int    numsym;
  2876.  
  2877.     strcpy(buf, p);
  2878.     DISPOSE(tkn);
  2879.     while (1)  {
  2880.         if (tkn = gNextToken(fobj))
  2881.             p = gStringValue(tkn);
  2882.         else
  2883.             break;
  2884.         if (*p == ';'  ||  *p == '}')
  2885.             break;
  2886.         strcat(buf, " ");
  2887.         strcat(buf, p);
  2888.         DISPOSE(tkn);
  2889.     }
  2890.     if (!tkn  ||  *p != ';')  {
  2891.         ErrorCode = 1;
  2892.         vPrintf(stdoutStream, "Missing ; after variable declaration in defclass.\n");
  2893.         if (tkn)
  2894.             DISPOSE(tkn);
  2895.         return;
  2896.     }
  2897.     DISPOSE(tkn);
  2898.     numsym = get_var(var, buf);
  2899.     strcat(buf, ";");
  2900.     if (numsym == 1) {
  2901.         memmove(buf+7, buf, strlen(buf)+1);
  2902.         memcpy(buf, "object ", 7);
  2903.     }
  2904. /*    add_underscore(buf);        */
  2905.     gAddLast(idecls, gNewWithStr(String, buf));
  2906.     if (!gAdd(ivars, tkn=gNewWithStr(String, var)))  {
  2907.         vPrintf(stdoutStream, "Class/instance variable name %s is multiply defined.\n", gStringValue(tkn));
  2908.         ErrorCode = 1;
  2909.         DISPOSE(tkn);
  2910.         return;
  2911.     }
  2912.     if (gFind(ovars, tkn))  {
  2913.         vPrintf(stdoutStream, "Class/instance variable name %s is multiply defined.\n", gStringValue(tkn));
  2914.         ErrorCode = 1;
  2915.     }
  2916. }
  2917.  
  2918. static    int    get_var(char *var, char *buf)
  2919. {
  2920.     char    *p, *e, save='\0', *sp = NULL;
  2921.     int    numsym = 0;
  2922.  
  2923.     *var = '\0';
  2924.  
  2925.     /*  get rid of arguments to pointers to functions  */
  2926.  
  2927.     for (p=buf ; *p ; ++p)
  2928.         if (*p == ')'  &&  p[1] == ' '  &&  p[2] == '('  ||  *p == '[')  {
  2929.             sp = p;
  2930.             save = *sp;
  2931.             *sp = '\0';
  2932.             break;
  2933.         }
  2934.  
  2935.     /*  find begining and end of last symbol  */
  2936.  
  2937.     for (e=p=NULL ; *buf ; )
  2938.         if (istart(*buf))  {
  2939.             p = buf++;
  2940.             while (irest(*buf))
  2941.                 buf++;
  2942.             e = buf;
  2943.             numsym++;
  2944.         } else
  2945.             buf++;
  2946.  
  2947.     if (p)  {
  2948.         char    s = *e;
  2949.         *e = '\0';
  2950.         strcpy(var, p);
  2951.         *e = s;
  2952.     }  else  {
  2953.         ErrorCode = 1;
  2954.         vPrintf(stdoutStream, "Invalid variable declaration in defclass.\n");
  2955.     }
  2956.     if (sp)
  2957.         *sp = save;
  2958.     return numsym;
  2959. }
  2960.  
  2961. #if 0
  2962.  
  2963. static    void    add_underscore(char *buf)
  2964. {
  2965.     char    *p, *e, save, *sp = NULL;
  2966.  
  2967.     /*  get rid of arguments to pointers to functions  */
  2968.  
  2969.     for (p=buf ; *p ; ++p)
  2970.         if (*p == ')'  &&  p[1] == ' '  &&  p[2] == '(')  {
  2971.             sp = p;
  2972.             save = *sp;
  2973.             *sp = '\0';
  2974.             break;
  2975.         }
  2976.  
  2977.     /*  find begining and end of last symbol  */
  2978.  
  2979.     for (p=NULL ; *buf ; buf++)
  2980.         if (istart(*buf))  {
  2981.             p = buf++;
  2982.             while (irest(*buf))
  2983.                 buf++;
  2984.             e = buf;
  2985.         }
  2986.  
  2987.     if (sp)
  2988.         *sp = save;
  2989.     if (p)  {
  2990.         memmove(p+1, p, strlen(p)+1);
  2991.         *p = '_';
  2992.     }
  2993. }
  2994.  
  2995. #endif
  2996.  
  2997. static    void    pp_init_section(object tkn, char *p, object fobj, object init)
  2998. {
  2999.     if (!valid_symbol(p))  {
  3000.         ErrorCode = 1;
  3001.         gPuts(stdoutStream, "Invalid init syntax in defclass.\n");
  3002.         DISPOSE(tkn);
  3003.         return;
  3004.     }
  3005.     gChangeStrValue(init, p);
  3006.     DISPOSE(tkn);
  3007.     if (tkn = gNextToken(fobj))
  3008.         p = gStringValue(tkn);
  3009.     if (!tkn  ||  *p != ';')  {
  3010.         ErrorCode = 1;
  3011.         gPuts(stdoutStream, "Missing ; in init section of defclass.\n");
  3012.     }
  3013.     if (tkn)
  3014.         DISPOSE(tkn);
  3015. }
  3016.  
  3017. static    char    *getword(char *s, char *w, char c)
  3018. {
  3019.     register int    i;
  3020.     
  3021.     while (*s  &&  !istart(*s))
  3022.         ++s;
  3023.     if (!*s)
  3024.         return NULL;
  3025.     for (i=0 ; ++i <= MAXWORDSZ && (irest(*s)  ||  *s == ':'  ||  c  &&  *s != c) ; )
  3026.         *w++ = *s++;
  3027.     *w = '\0';
  3028.     return s;
  3029. }
  3030.  
  3031. /*  get a line - append continuation lines - get rid of comments, strings
  3032.     and code between braces  */
  3033.  
  3034. static    int    get_line(object fobj, char *line)
  3035. {
  3036.     char    *tbuf;
  3037.     static    char    buf[10000];
  3038.     int    something = 0, i;
  3039.  
  3040.     tbuf = buf;
  3041.     while (1)  {
  3042.         if (!gGets(fobj, tbuf, BUFSIZE))
  3043.             break;
  3044.         CurrentLine++;
  3045.         something = 1;
  3046.         i = strlen(tbuf) - 1;
  3047.         while (i >= 0  &&  (tbuf[i] == '\n' ||  tbuf[i] == '\r'))
  3048.             i--;
  3049.         if (i < 0  ||  tbuf[i] != '\\')  {
  3050.             tbuf[i+1] = '\0';
  3051.             break;
  3052.         }
  3053.         tbuf[i] = '\0';
  3054.         tbuf += i;
  3055.     }
  3056.     process_line(line, buf);
  3057.     return something;  /*  0=eof  */
  3058. }
  3059.  
  3060. #define IS(a, b)    *s == a  &&  s[1] == b
  3061.  
  3062. static    char    *gettoken(object fobj)
  3063. {
  3064.     register int    i;
  3065.     char    *w;
  3066.     static    char    buf[10000], token[BUFSIZE], *s;
  3067.  
  3068.     if (!fobj)  {        /*  reset state  */
  3069.         s = buf;
  3070.         *buf = '\0';
  3071.         CurrentLine = 0;
  3072.         process_line(NULL, NULL); /*  init to code state  */
  3073.         return NULL;
  3074.     }
  3075.     while (isspace(*s)  ||  !*s)
  3076.         if (!*s)  {
  3077.             if (get_line(fobj, buf))
  3078.                 s = buf;
  3079.             else
  3080.                 return NULL; /*  no more  */
  3081.         } else
  3082.             s++;
  3083.     w = token;
  3084.     if (istart(*s))        /*  is identifier  */
  3085.         for (i=0 ; ++i <= MAXWORDSZ  &&  irest(*s) ;)
  3086.             *w++ = *s++;
  3087.     else            /*  something other than an identifier  */
  3088.  
  3089.         if (*s == '<'  &&  s[1] == '<'  &&  s[2] == '='  ||
  3090.             *s == '.'  &&  s[1] == '.'  &&  s[2] == '.'  ||
  3091.             *s == '>'  &&  s[1] == '>'  &&  s[2] == '=')  {
  3092.             *w++ = *s++;
  3093.             *w++ = *s++;
  3094.             *w++ = *s++;
  3095.         } else if (IS('*', '=')  ||
  3096.                IS('/', '=')  ||
  3097.                IS('%', '=')  ||
  3098.                IS('+', '=')  ||
  3099.                IS('-', '=')  ||
  3100.                IS('&', '=')  ||
  3101.                IS('^', '=')  ||
  3102.                IS('|', '=')  ||
  3103.                IS('&', '&')  ||
  3104.                IS('|', '|')  ||
  3105.                IS('=', '=')  ||
  3106.                IS('!', '=')  ||
  3107.                IS('<', '<')  ||
  3108.                IS('>', '>')  ||
  3109.                IS('<', '=')  ||
  3110.                IS('>', '=')  ||
  3111.                IS('-', '-')  ||
  3112.                IS('+', '+')  ||
  3113.                IS('-', '>'))  {
  3114.             *w++ = *s++;
  3115.             *w++ = *s++;
  3116.         } else if (*s == '"'  ||  *s == '\'')  {
  3117.             char    type = *s;
  3118.             *w++ = *s++;
  3119.             while (*s  &&  *s != type)  {
  3120.                 *w++ = *s;
  3121.                 if (*s == '\\'  &&  s[1])
  3122.                     *w++ = *++s;
  3123.                 ++s;
  3124.             }
  3125.             if (*s)
  3126.                 *w++ = *s++;
  3127.         } else if (isdigit(*s)  ||  *s == '.'  &&  isdigit(s[1]))  {
  3128.             while (isdigit(*s)  ||  *s == '.'  ||  *s == 'e'  ||  *s == 'E'
  3129.                    ||  ((*s=='-' ||  *s=='+')  &&
  3130.                     (s[-1] == 'e'  ||  s[-1] == 'E')) )
  3131.                 *w++ = *s++;
  3132.             if (*s == 'u'  ||  *s == 'U'  ||  *s == 'l'  ||  *s == 'L')
  3133.                 *w++ = *s++;
  3134.             if (*s == 'u'  ||  *s == 'U'  ||  *s == 'l'  ||  *s == 'L')
  3135.                 *w++ = *s++;
  3136.         } else
  3137.             *w++ = *s++;
  3138.     *w = '\0';
  3139.     /*  printf("Token = %s\n", token);  */
  3140.     return token;
  3141. }
  3142.  
  3143. static    char    *gettype(char *s, char *w)
  3144. {
  3145.     register int    i;
  3146.     char    *b, *bw = w;
  3147.     
  3148.     while (*s  &&  isspace(*s))
  3149.         ++s;
  3150.     if (!*s  ||  !istart(*s))
  3151.         return NULL;
  3152.     b = s;
  3153.     while (*s  &&  *s != '(')
  3154.         ++s;
  3155.     if (*s != '(')
  3156.         return NULL;
  3157.     while (s > b  &&  !irest(*s))
  3158.         --s;
  3159.     while (s > b  &&  irest(*s))
  3160.         --s;
  3161.     if (s == b)
  3162.         return NULL;
  3163.     while (s > b  &&  isspace(*s))
  3164.         --s;
  3165.     ++s;
  3166.     for (i=0 ; ++i <= MAXWORDSZ  &&  b < s ; )
  3167.         *w++ = *b++;
  3168.     *w = '\0';
  3169.     compress(bw);
  3170.     return s;
  3171. }
  3172.  
  3173. static    void    compress(char *f)
  3174. {
  3175.     int    state = 1;    /* 1=not space, 0=space  */
  3176.     char    *t = f;
  3177.  
  3178.     for ( ; *f ; ++f)
  3179.         if (state)
  3180.             if (isspace(*f))  {
  3181.                 state = 0;
  3182.                 *t++ = ' ';
  3183.             }  else 
  3184.                 *t++ = *f;
  3185.         else
  3186.             if (!isspace(*f))  {
  3187.                 *t++ = *f;
  3188.                 state = 1;
  3189.             }
  3190. }
  3191.  
  3192. #ifdef    unix
  3193. #define    RPLUS    "r+"
  3194. #else
  3195. #define RPLUS    "r+b"
  3196. #endif
  3197.  
  3198. static    int    touch(char *f)
  3199. {
  3200.     FILE    *fp;
  3201.     int    c, err=0;
  3202.  
  3203.     if (fp = fopen(f, RPLUS))  {
  3204.         fseek(fp, 0L, 2);
  3205.         if (ftell(fp) == 0L)
  3206.             err = 1;
  3207.         else  {
  3208.             fseek(fp, 0L, 0);
  3209.             c = fgetc(fp);
  3210.             fseek(fp, 0L, 0);
  3211.             fputc(c, fp);
  3212.         }
  3213.         fclose(fp);
  3214.     }   else
  3215.         err = 1;
  3216.     if (!err  &&  !Quiet)
  3217.         vPrintf(stdoutStream, "Touched %s\n", f);
  3218.     return err;
  3219. }
  3220.  
  3221. char    *trunc_mname(char *mname)
  3222. {
  3223.     char    *p = mname;
  3224.  
  3225.     while (*p  &&  *p != '_')
  3226.         p++;
  3227.     return *p ? p+1 : mname;
  3228. }
  3229.  
  3230. #if 0
  3231.  
  3232. char    *trunc_mname(char *mname)
  3233. {
  3234.     static    char    buf[80];
  3235.     int    len = strlen(mname), p = strlen(MPREFIX), s = strlen(MSUFFIX);
  3236.  
  3237.     if (p  &&  !strncmp(MPREFIX, mname, p))  {
  3238.         mname += p;
  3239.         len -= p;
  3240.     }
  3241.     strcpy(buf, mname);
  3242.     if (s  &&  len > s  &&  !strncmp(MSUFFIX, buf+(len-s), s))
  3243.         buf[len-s] = '\0';
  3244.     return buf;
  3245. }
  3246.  
  3247. static    objrtn    set_name(char *p, object seq)
  3248. {
  3249.     object    arg = gNext(seq);
  3250.     if (!arg)
  3251.         return arg;
  3252.     if (p[2] == 'p')
  3253.         strcpy(MPREFIX, gStringValue(arg));
  3254.     else if (p[2] == 's')
  3255.         strcpy(MSUFFIX, gStringValue(arg));
  3256.     else 
  3257.         return arg;
  3258.     return gNext(seq);
  3259. }    
  3260.  
  3261. #endif
  3262.     
  3263. static    void    copyright(object fobj)
  3264. {
  3265.     gPuts(fobj, "\n\n/*  Copyright (c) 1993-1996 Algorithms Corporation  */\n");
  3266.     gPuts(fobj, "/*  All rights reserved.  */\n\n\n");
  3267. }
  3268.  
  3269. static    int    class_source(char *p)
  3270. {
  3271.     char    *ext = file_extension(p);
  3272.  
  3273.     return (streq(ext, "d")  ||
  3274.         streq(ext, "D")  ||
  3275.         streq(ext, "dd")  ||
  3276.         streq(ext, "DD")  ||
  3277.         streq(ext, "n")  ||
  3278.         streq(ext, "N")  ||
  3279.         streq(ext, "nn")  ||
  3280.         streq(ext, "NN")  ||
  3281.         streq(ext, "i")  ||
  3282.         streq(ext, "ii")  ||
  3283.         streq(ext, "I")  ||
  3284.         streq(ext, "II"));
  3285. }
  3286.  
  3287. /*                                      
  3288.  *
  3289.  *      Copyright (c) 1993-1996 Algorithms Corporation
  3290.  *      3020 Liberty Hills Drive
  3291.  *      Franklin, TN 37067
  3292.  *
  3293.  *      ALL RIGHTS RESERVED.
  3294.  *
  3295.  *      
  3296.  *      
  3297.  */
  3298.  
  3299.